Spam Filtering Email Aliases Using SpamAssassin and Procmail

by Nick Christenson
September 21, 2010

Introduction

Email spam is a scourge on the Internet. It's difficult for anyone to run a non-trivial email service without installing some form of anti-spam system. For Unix/Linux based systems, perhaps the most popular comprehensive open source solution is SpamAssassin in conjunction with the email filtering program/devliery agent Procmail.

The basic architecture has email coming into your Mail Transfer Agent (MTA), such as sendmail, postfix, or whatever. The MTA passes the email it receives to SpamAssassin for evaluation. SA goes through the messge evaluating its rules and assigning a score for the message. If the message scores above some threshold, it's tagged as spam. If not, it's tagged as a clean message. SpamAssassin does not filter out email itself, it just marks the message as spam or not.

If the destination of an email message is a local mailbox, the MTA hands off the email to a Local Delivery Agent (LDA). For Linux, the default LDA is Procmail. For sendmail-based installations on other Unices, Procmail can be used to replace the default LDA. As an LDA, Procmail has the advantage that it can be programmed to filter email and process messages with different traits in different ways. As such, it can detect which email SpamAssassin has flagged as spam and deliver it somewhere different from the default email spool, or it can discard such email entirely.

This all works fine, but there are a lot of email messages flowing through many mail servers that aren't locally delivered. So while these are checked for their spam status by SpamAssassin, they won't be segregated as spam because they don't pass through Procmail.

One category of email messages that doesn't get filtered are those bound for non-local recipients as specified in the aliases file. This article describes how to use Procmail on a SpamAssassin-enabled system to filter out SA-flagged spam sent to non-local aliases.

Setup

Obviously, you need an email server that is set up to pass its email through SpamAssassin. Also you need Procmail to be installed. Third, you need an email service that consults the /etc/mail/aliases (or /etc/aliases) file. All of this is outside of the scope of this article.

The first thing we'll do is some simple setup on the system. Create a directory somewhere, something like /etc/mail/procmail-aliases, owned and writable by the same owner as the aliases file. The solution will create one file in this directory for each alias.

Entries in the aliases file generally take one of the following three formats:

address1:	user1,user2@example.com,user3@example.org
address2:	/var/spool/archives/outputfile
address3:	"|/usr/local/bin/someprogram address3"

Replace the right hand side so it looks like the following:

address1:	"|/path/to/procmail -m /etc/mail/procmail-aliases/address1"

Then put the following in the file /etc/mail/procmail-aliases/address1:

:0H
* ^X-Spam-Flag: YES
* ^X-Spam-Status: Yes,
/dev/null

:0
*
! user1 user2@example.com user3@example.org

Translated into English, the first rule checks for the X-Spam-* lines SpamAssassin inserts into the mail header. If they indicate the message is spam, it's sent to /dev/null. Otherwise, it is sent to the user1, user2@example.com, and user3@example.org email addresses.

We can make this simple procmail recipe work for the third alias listed above by changing the last line. Simply change it to:

| /usr/local/bin/someprogram address3

When logging the message to a file, as in the second alias, we list the file name in the last line, but we need to make sure we lock the file to prevent two mail deliveries from attempting to write to the file at the same time. We do this by adding a trailing colon to the line with the leading colon, so the whole recipe looks like this:

:0H
* ^X-Spam-Flag: YES
* ^X-Spam-Status: Yes,
/dev/null

:0:
*
/var/spool/archives/outputfile

Finally, if you want to save the spam for future inspection, then we need to save that to a file, and then we ought to lock it. So, the recipe now looks like this:

:0H:
* ^X-Spam-Flag: YES
* ^X-Spam-Status: Yes,
/var/spool/archives/outputfile-spamfolder

:0:
*
/var/spool/archives/outputfile