Integrating SpamAssassin into Postfix using spamd
Wiki Markup |
---|
The easiest way to integrate postfix and spamassassin is to use spamd in an \[http://www.postfix.org/FILTER_README.html after-queue\] inspection. This configuration does not allow rejecting messages within the SMTP transaction, so it unfortunately contributes to backscatter email. On the other hand, it has important performance advantages over \[http://www.postfix.org/SMTPD_PROXY_README.html before-queue\] inspection. |
First, edit /etc/postfix/master.cf, find the
...
No Format |
---|
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (50)
# ==========================================================================
...
spamassassin
unix - n n - - pipe
flags=Rq user=nobody argv=/path/to/spamc -u ${recipient} -e /path/to/postfix/sendmail -oi -f ${sender} ${recipient}
|
Notice "-u ${recipient}" added. Otherwise "username" field in database will always appear as user which postfix is invoking spamc(in this example it is 'nobody').
Note that this exact method of invoking SpamAssassin is not very robust. Postfix's pipe error behavior is as follows:
- If the
exec()
fails (e.g.,/path/to/spamc
is incorrect), Postfix will bounce the message. - If the command returns
EX_OSERR
orEX_TEMPFAIL
(defined in/usr/include/sysexits.h
), Postfix will defer the message. - If the command returns
EX_OK
, Postfix will deliver the message. - If the command returns any other error code, Postfix wil bounce the message.
With spamc -e
, spamc will return EX_OK
when spamd is unavailable but sendmail is working, so Postfix will deliver the message. You probably want it to be deferred instead. This is not possible with spamc directly, but you can do so with a simple script. Replace the lines above with:
No Format |
---|
spamassassin
unix - n n - - pipe
flags=Rq user=nobody argv=/path/to/filter.sh -oi -f ${sender} ${recipient}
|
and create a filter.sh
as follows:
No Format |
---|
#!/bin/sh
SENDMAIL="/usr/sbin/sendmail -i"
SPAMASSASSIN=/usr/bin/spamc
# Exit codes from <sysexits.h>
EX_TEMPFAIL=75
EX_UNAVAILABLE=69
umask 077
OUTPUT="`mktemp mailfilter.XXXXXXXXXX`"
if [ "$?" != 0 ]; then
/usr/bin/logger -s -p mail.warning -t filter \
"Unable to create temporary file."
exit $EX_TEMPFAIL
fi
# Clean up when done or when aborting.
trap "rm -f $OUTPUT" EXIT SIGTERM
$SPAMASSASSIN -x > $OUTPUT
return="$?"
if [ "$return" == 1 ]; then
echo "Message content rejected"
exit $EX_UNAVAILABLE
elif [ "$return" != 0 ]; then
/usr/bin/logger -s -p mail.warning -t filter \
"Temporary SpamAssassin failure (spamc return $return)"
exit $EX_TEMPFAIL
fi
$SENDMAIL "$@" < $OUTPUT
exit $?
|
You still must be careful that the script is in the right place and executable or email will bounce. However, this will defer messages on most failures.
Wiki Markup |
---|
A more complex |
Wiki Markup |
Note that this exact method of invoking [SpamAssassin] is not very robust. Should spamc for some reason fail to start, Postfix will start bouncing mail. A more robust but also more I/O-intensive solution is the one proposed in the \[http://www.postfix.org/FILTER_README.html FILTER_README file\] that comes with the Postfix distribution. See \[IntegratePosfixViaSpampd\] for one approach. |
...