One complaint that I've heard from some of my email users is that they think it's really annoying that spam systems will often classify inbound reply messages as spam. What do I mean by inbound reply messages? Let's say jane@foo.net sends a message to mike@bar.net. When mkie@bar.net replies to that message, the mail system that jane@foo.net uses should automaticallly know that mike@bar.net is a trusted person, and all messages from him to come through without being labelled as spam.

This is what I call 'Auto Whitelisting': Every time you send a message to someone, that recipient's email address is recorded. Any time you receive a message from that person, the mail system will recognize that you had previously sent them a message, and allow their email to be delivered directly to your inbox, bypassing the spam filters.

Is this type of a system foolproof? No. It would be easy for a spam system to make a mail message appear as though it is coming from an email address that you had previously sent email to. However, this doesn't appear to happen very often, so I implemented the following system:

Requirements, Pieces and Parts

courier mail server v0.45.5 or newer
perl v5.8 or newer
Julian Mehnle's Courier::Filter perl modules

I installed the Courier::Filter package using CPAN:

> perl -MCPAN -e shell
cpan> install Courier::Filter

Keep track of where Courier::Filter gets installed, becuase you'll need to know this later. In my case, the package was installed into /usr/local/lib/perl5/site_perl/5.8.4/Courier. Once installed, you will need to configure the Courier::Filter module so that it knows where your Courier server is installed. The config file is 'Config.pm', and should be located in the Courier::Filter installation folder. To this file, I added the following variable definitions, because my Courier server is installed at /usr/lib/courier:

use constant COURIER_CONFIG_DIR     => '/usr/lib/courier/etc';
use constant COURIER_RUNTIME_DIR    => '/usr/lib/courier/var';

The next thing you need to do is register Courier::Filter with Courier's filtering system, as per the Courier::Filter deployment instructions. For me, this involved creating a configuration file called /usr/lib/courier/etc/filters/pureperlfilter.conf with the following contents:

use Courier::Filter::Logger::Syslog;
use Courier::Filter::Module::AutoWhitelist;
use Courier::Filter::Module::WhitelistCheck;

$options = {
        name => 'courier-filter',
        logger => Courier::Filter::Logger::Syslog->new(),
        modules => [ Courier::Filter::Module::AutoWhitelist->new(),
                     Courier::Filter::Module::WhitelistCheck->new() ]
};

What does all of that do? It will basically tell the Courier::Filter system to register my two filter scripts (AutoWhitelist.pm and WhitelistCheck.pm) with the filter system. They aren't yet activated, but we'll do that in a later step. The next thing you'll need to do is create a symlink to the pureperlfilter controller script where Courier will be looking for it. For me, this meant:

> cd /usr/lib/courier/etc/filters/active
> ln -s /usr/local/bin/pureperlfilter

That's the basic setup for Courier::Filter. Now you need to install the three scripts that make up my Auto Whitelisting sytem. Download the files to a local directory, and unpack them. Here is where they need to be installed:

AutoWhitelist.pm -> /usr/local/lib/perl5/site_perl/5.8.4/Courier/Filter/Module
WhitelistCheck.pm -> /usr/local/lib/perl5/site_perl/5.8.4/Courier/Filter/Module
whitelistverify.pl -> /usr/lib/courier/libexec/filters

Before you go much further, you should take a look inside each of these files. There are two DB files that are used in their processing, and you need to configure the scripts to create those files in directories that make sense for your system, and in which the mail server will have permissios to create/modify them. The two files are 'whitelist.db', which will contain the mappings of sender-recipient relationships, and 'whitelistresult.db', which is used for transient storage of whitelist verification results while messages are being processed. By default, the scripts will look for these files in /tmp, but that is probably not a very safe place to put them.

Next, you need to modify your system-wide Maildrop filter script to check for the results of the Auto Whitelisting, and handle the message appropriately. If a message passes the tests, the scripts will add a 'X-Whitelist-Result:' header to the message with a value of either 'PASS' or 'FAIL'. Based on that header, I then decide whether or not to deliver the message to the inbox or allow it to be analyzed by additional spam filters. My /usr/lib/courier/etc/maildroprc file looks like this:

exception {
        xfilter "/usr/lib/courier/libexec/filters/whitelistverify.pl"
}

if ( !/^X-Whitelist-Result: *FAIL/:h )
{
        if ( /^X-Whitelist-Result: *PASS/:h )
        {
                exception {
                        to "$HOME/Maildir"
                }
        }
}

exception {
        xfilter "/usr/local/bin/spamassassin"
}

 

The first 'xfilter' command will take the message, and determine if it passed the whitelisted test performed in the Courier::Filter::Module::WhitelistCheck module. Depending on the result of that test, the whitelistverify.pl script will add the appropriate 'X-Whitelist-Result' header. The next lines in the maildroprc script will then make sure that before the message is placed into the inbox, that it does not contain a failure header, and does contain a pass header. This should protect against people who try to insert a fake 'PASS' header.

If the message does contain a FAIL header, it will then continue with the usual spam procecssing steps (spamassassin, in this case).

The last step in this procedure is to activate the system and start testing mail routing to make sure that everything still works.

> cd /usr/lib/courier/sbin
> ./courierfilter start
> less /var/log/mail.log

It's then time to start sending messages inbound and outbound, making sure that everything works. Some of the things to look out for are: