Linux SysAdmin & DevOps

Spamassassin filter - Postfix Mail server

Postfix - one of the most used open source mail server software. Let’s create a simple spam filter running on your linux box using SpamAssassin and Postfix. It basically works on any linux distribution which has these 2 packages installed.

I am going to assume that you already have a fresh install of postfix and spamassasin.

Spamassasin: how to create a simple spam filter using bash and spamc

First we have to create a linux user. The spam filter will run under that user. I am going to use user: spamcheck for now:

useradd -d /var/spamcheck -m -c "SpamAssasin Filter" -s /bin/false spamcheck

Then we create a filter file which invoques spamassassin’s binary spamc. Name the file spamcheck for example and create it in /bin/spamcheck with the following content:

# -----------------------------------------------------------------
# File: spamcheck
# Purpose: SpamAssassin shell-based filter
# Location: /bin
# Usage: Call this script from master.cf (Postfix)
# Certified: CentOS (any version), Spamassassin 3.x, Postfix
# -----------------------------------------------------------------
 
# Variables
SENDMAIL="/usr/sbin/sendmail -i"
EGREP=/bin/egrep
 
# Exit codes from
EX_UNAVAILABLE=69
 
# Number of *'s in X-Spam-level header needed to sideline message:
# (Eg. Score of 5.5 = "*****" )
SPAMLIMIT=10
 
# Clean up when done or when aborting.
trap "rm -f /var/filter/out.$$" 0 1 2 3 15
 
# Pipe message to spamc
cat | /usr/bin/spamc -u filter | sed 's/^\.$/../' > /var/filter/out.$$
 
# Are there more than $SPAMLIMIT stars in X-Spam-Level header? :
if $EGREP -q "^X-Spam-Level: \*{$SPAMLIMIT,}" < /var/filter/out.$$
then
# Option 1: Move high scoring messages to sideline dir so
# a human can look at them later:
# mv out.$$ $SIDELINE_DIR/`date +%Y-%m-%d_%R`-$$
 
# Option 2: Divert to an alternate e-mail address:
$SENDMAIL [email protected] < /var/filter/out.$$
 
# Option 3: Delete the message
# rm -f /var/filter/out.$$
else
$SENDMAIL "$@" < /var/filter/out.$$
fi
 
# Postfix returns the exit status of the Postfix sendmail command.
exit $?

Now set the right permissions the SpamAssasin shell script and /var/spamcheck folder:

chown root:spamcheck /bin/spamcheck
chmod 755 /bin/spamcheck
chmod 777 /var/spamcheck

Now go to postfix configuration folder (/etc/postfix) and edit master.cf file. Add somewhere at the beggining of the file the entry bellow:

# Spam Check with SpamAssassin
spamcheck unix - n n - 10 pipe
flags=Rq user=filter argv=/bin/spamcheck -f ${sender} -- ${recipient}

Spamassassin filter test

Save the file and reload postfix (service postfix reload). Spamassassin daemon (spamd) daemon should be running in order to have a working spam filter for postfix. You can check the status of spamd using:

service spamd status
systemctl status spamd

Send yourself an email and check postfix logs (tail -f /var/log/maillog) to see if the filter is working. If you’re seeing something like in the link bellow, then you succeded:

(queue active)
Jun 26 21:34:38 zira spamd[9697]: spamd: connection from localhost [127.0.0.1] at port 42727
Jun 26 21:34:38 zira spamd[9697]: spamd: processing message <CANLJf1oeYowX_7+_mV-sGOD4apFbWXvYmmX3PTWZEirSgNyCkg@mail.gmail.com> for filter:496
Jun 26 21:34:39 zira postfix/smtpd[20175]: disconnect from mail-ie0-f171.google.com[209.85.223.171]
Jun 26 21:34:40 zira spamd[9697]: spamd: clean message (-7.5/5.0) for filter:496 in 1.8 seconds, 1911 bytes.
Jun 26 21:34:40 zira spamd[9697]: spamd: result: . -7 - AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,HTML_MESSAGE,MTX_FAIL,MTX_NONE,RCVD_IN_DNSWL_LOW,SPF_PASS,USER_IN_WHITELIST_TO scantime=1.8,size=1911,user=filter,uid=496,required_score=5.0,rhost=localhost,raddr=127.0.0.1,rport=42727,mid=<CANLJf1oeYowX_7+_mV-sGOD4apFbWXvYmmX3PTWZEirSgNyCkg@mail.gmail.com>,bayes=0.000000,autolearn=ham
Jun 26 21:34:40 zira spamd[25164]: prefork: child states: II
Jun 26 21:34:40 zira postfix/pickup[20149]: E407526185B: uid=502 from=<[email protected]>
Jun 26 21:34:40 zira postfix/cleanup[20186]: E407526185B: message-id=<CANLJf1oeYowX_7+_mV-sGOD4apFbWXvYmmX3PTWZEirSgNyCkg@mail.gmail.com>
Jun 26 21:34:40 zira opendkim[1115]: E407526185B: no signing table match for '[email protected]'
Jun 26 21:34:40 zira postfix/pipe[20187]: 80F39261795: to=<myemail@server_with_spam_filter>, relay=spamcheck, delay=2.5, delays=0.51/0.01/0/2, dsn=2.0.0, status=sent (delivered via spamcheck service)
Jun 26 21:34:40 zira postfix/qmgr[20148]: 80F39261795: removed