Using ClamAV and SpamAssassin with Postfix (without Amavis)

Many people use AMaViS or amavisd-new to combine Postfix with ClamAV and SpamAssassin. However, Amavis takes huge amounts of CPU time and memory. Also, it’s quite slow and difficult to configure, so another solution without Amavis would be interesting.

In this article, I will only discuss server-wide solutions without procmail because it can’t be used with virtual domain mailboxes.

It’s possible to use a shell script that calls ClamAV and SpamAssassin as a Postfix content filter:

/opt/mail-scanner

#!/bin/sh

EX_OK=0
EX_BOUNCE=69
EX_DEFER=75

SENDMAIL="/usr/sbin/sendmail -G -i"

SPAM_DIR=/home/mailscan/spam
VIRUS_DIR=/home/mailscan/viruses

function cleanup {
for fname in ${tmpfile[@]}
do
rm -f $fname
done
}

for ((i=0;i<2;i++))
do
fname=`mktemp -p /tmp mail-scanner.XXXXXXXX`
if [ "$?" != 0 ]; then
logger -s -p mail.warning -t scanner "Unable to create temporary file."
exit $EX_DEFER
fi
tmpfile[$i]=$fname
trap cleanup EXIT TERM
done

cat >${tmpfile[0]}

# check for viruses

clamdscan - <${tmpfile[0]} >${tmpfile[1]}
return="$?"
if [ "$return" = 1 ]; then
virus=`grep FOUND ${tmpfile[1]}`
logger -p mail.info "Message rejected by ClamAV: $virus"
mv ${tmpfile[0]} `mktemp -p $VIRUS_DIR virus.XXXXXXXX`
exit $EX_OK             # discard (exit without re-injecting)
elif [ "$return" != 0 ]; then
logger -s -p mail.warning -t scanner "Temporary ClamAV failure (clamdscan returned $return)"
exit $EX_DEFER
fi

# check for spam

spamc -x <${tmpfile[0]} >${tmpfile[1]}
return="$?"
if [ "$return" = 1 ]; then
logger -p mail.info "Message rejected by SpamAssassin"
mv ${tmpfile[0]} `mktemp -p $SPAM_DIR spam.XXXXXXXX`
exit $EX_OK             # discard (exit without re-injecting)
elif [ "$return" != 0 ]; then
logger -s -p mail.warning -t scanner "Temporary SpamAssassin failure (spamc returned $return)"
exit $EX_DEFER
fi

# deliver

$SENDMAIL "$@" <${tmpfile[1]}
exit $?

All you need is to copy this script to a location, let’s say /opt or /usr/local/bin and then edit the master.conf file of your Postfix so that:

  • the smtp service takes a content filter service (called “scanner” here, but you may use any name):
    smtp  inet  n  -  -  -  -  smtpd -o content_filter=scanner:dummy
  • the content filter service is defined:
    scanner   unix  -       n       n       -       5       pipe
      flags=Rq user=mailscan argv=/opt/mail-scanner -f $sender -- $recipient

Leave a Reply

Image | WordPress Themes