Sendmail + Cyrus + Procmail(?) + SpamAssassin
Andrew Swartz
awswartz at acsalaska.net
Wed Jun 21 18:38:17 UTC 2006
I don't know if anyone is still interested, but I found a solution to
this problem. My mail goes Sendmail-->Procmail-->CyrusIMAP.
There are numerous discussions of how to configure the
Sendmail-->Procmail portion, so I'll skip that.
The problem lies in the Procmail-->Cyrus part. Sendmail and/or Procmail
insists on adding a "From" line to the top of the message, and this
causes an error when trying to pass the message from the procmailrc file
to /usr/lib/cyrus-imapd/deliver. So I wrote a little C-program that the
email can be piped through (removing the "From" line); the resulting
message is passed to /usr/lib/cyrus-imapd/deliver.
Here is my ~/.promailrc file. Note that all mail is first delivered to
the user's CyrusIMAP box, then it goes through the procmail checks.
This is because if I don't do this, then all mail that fails all the
conditions (recipes) gets shoved into /usr/local/mail/~, which is
basically a black hole if you are using Cyrus.
# This file is: ~/.procmailrc
#
# REQUIREMENTS:
# 1) cyrus-imap (specifically, "/usr/lib/cyrus-imapd/deliver").
# 2) the C-program "rmfromln" in a reachable place (like
/usr/local/bin).
# rmfromln: the email argument is piped in; if the email
message
# has been appended with starting "From" line, then this line is
# removed, otherwise the message remains unchanged.
LOGFILE=/home/r2/procmail.log
###############################################################################
# This is the default action; it delivers the email to the imap mailbox,
# and thus this happens regardless of the success|failure of the
recipes.
# RATIONAL: every email MUST have a "To" field, otherwise sendmail would
# not have passed it to us!?
:0 c
* ^To:.
| rmfromln | /usr/lib/cyrus-imapd/deliver $LOGNAME
###############################################################################
:0
* ^Subject:.*(callalert|CALLALERT)
* ^Subject:.*(on|ON)
| /root/scripts/callalert on
:0
* ^Subject:.*(callalert|CALLALERT)
* ^Subject:.*(off|OFF)
| /root/scripts/callalert off
ALSO: I've attached the C-program "rmfromln" (and it's source code)
which removes the "From" line (if it is present).
-Andy Swartz
-------------- next part --------------
A non-text attachment was scrubbed...
Name: rmfromln
Type: application/octet-stream
Size: 12975 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-questions/attachments/20060621/0444f1aa/rmfromln.obj
-------------- next part --------------
/* NEW plan:
1) create a temp io-stream with tempfile()
2) read in from stdin and out to temp until EOL (or EOF)
3) dynamically create a string of the appropriate length
(i.e. the number of characters written to temp-stream)
4) copy temp-stream to the new string
5) search the string for "From"
6) if found, copy the string to stdout
7) copy the remaining stdin to stdout until EOF reached.
*/
#include "stdio.h"
#include "string.h"
#include "stddef.h"
#include "stdlib.h"
// ###############################################
#define EOL '\n'
// ###############################################
main () {
char c;
int length;
int j;
FILE *tempstream;
char *tempstring;
// Create the temp-stream
tempstream = tmpfile();
// Read from stdin into tempstream until EOF or EOL is encountered.
length = 0;
rewind(tempstream);
while ((c=fgetc(stdin)) && (c != EOL)) {
fputc(c,tempstream);
length++;
}
// if no input, then just exit and do nothing.
if (length == 0)
exit(0);
// the above code did not put the EOL in the temp-stream, so add it.
fputc(EOL,tempstream);
length++;
// create the tempSTRING and copy the tempstream into it.
// tempstring = new string[length];
tempstring = (char *) calloc(length,sizeof(char));
rewind(tempstream);
for(j=0;j<length;j++)
tempstring[j] = fgetc(tempstream);
/* If we are at EOF, then there was no EOL, and thus no search for "From" is indicated;
so simply write the temp-string to stdout and exit. */
if (feof(stdin)) {
for (j=0;j<length;j++)
fputc(tempstring[j],stdout);
exit(0);
}
// If we got to here, we need to search temp-string for "From".
if (strstr(tempstring,"From") == NULL) {
/* i.e. "From" was NOT in the 1st line, so this line needs to
be output before the remaining stdin is transferred to stdout */
for (j=0;j<length;j++)
fputc(tempstring[j],stdout);
}
// dynamically allocated string is done, so free up the memory.
free (tempstring);
// now just transfer the remaining stdin to stdout.
c = getchar();
while (c != EOF) {
fputc(c,stdout);
c = getchar();
}
} /* End of Main */
More information about the freebsd-questions
mailing list