CustomFunction: WhiteListFutureSender

paddy paddy at PANICI.NET
Mon Nov 22 18:59:15 GMT 2004


I just knocked this up, and I thought maybe it might be worth sharing.
There's not a lot to it really (and what there is is largely
cut'n'paste from the existing examples).

The idea is to whitelist recipients of outgoing mail from known
(client) relays, for return mail.  When such an outgoing mail is
detected the value "<sender_ip>,<recipient>" is stored as the key in
a tied hash along with a value that can be increased by subsequent
hits, and aged by a cron job.  Probably +=1 is not what I'll end up
doing, but since I don't yet have a strategy, I've kept it simple.

No doubt, even in a snippet of code this size I've left some bugs.

!!! Caveat, Administrator !!!

That said, this is for 'Is Definitely Not Spam'.  I'm thinking
of trying to pick up the whitelist inside spamassassin for a
weighting instead.  And I can think of a lot more that could be done.

Incidentally, Julian, is there a simple way to hook a chain of
custom functions together?   Suppose there are several unrelated
CustomFunctions I wish to run at 'Always Last' can I write something

Always Looked-up Last = &CF1, &CF2, &CF3

Many thanks to Steve who pointed out sender-milter to me, which
does this almost as an afterthought but also a lot of cool stuff,
and Julian for MailScanner and superhuman support.

Praise, questions, comments, corrections, flames, whatever, all welcome.


%><----MIME WHAT'S THAT?-----

package MailScanner::CustomConfig;

use FileHandle;
BEGIN { @AnyDBM_File::ISA = qw(DB_File GDBM_File NDBM_File SDBM_File) }
use AnyDBM_File;

my $LockFile =  '/etc/MailScanner/wlfs.lock';
my $DB =        '/etc/MailScanner/wlfs.db';
my %wlfs_senders;

sub InitWLFS {


        my $fh = new FileHandle;
        unless ($fh->open('/etc/MailScanner/wlfs_senders')) {
                MailScanner::Log::WarnLog("Could not read wlfs_senders");
        while(<$fh>) {
                s/#.*$//;     # Remove comments
                s/\s+$//;     # and trailing whitespace
                s/^\s+//;     # and leading whitespace
                next if /^$/; # and blank lines
                # maybe check this is a valid ip address here ?
                MailScanner::Log::InfoLog("InitWLFS: %s", $_);
                $wlfs_senders{$_} = 1;

sub EndWLFS {

sub WLFS {
my($message) = @_;

        my $LockFileH = new FileHandle;
        WLFSopenlock($LockFileH, ">$LockFile");

        my %List;
        unless (tie %List, "AnyDBM_File", $DB, O_RDWR|O_CREAT, 0644) {
                print "wlfs: Could not open/create %s", $DBF;
                return 0;

        my $id = $message->{id};  # just for the logging, below
        my $ip = $message->{clientip};
        if ($wlfs_senders{$ip}) {
                # add recipients to the whitelist
                for $r (@{$message->{to}}){
                        MailScanner::Log::InfoLog("WLFS: %s : %s", $id, $r);
                        $List{"$ip,$r"} += 1 ;
        $f = $message->{from};
        $l = $List{"$ip,$f"};

        untie %List;

        return 1 if $l>1;
        return 0;

sub WLFSopenlock {
my($fh, $fn) = @_;

        if (open($fh, $fn)) {
                flock($fh, LOCK_EX);
        } else {
                print "Could not open file $fn: %s", $!;

sub WLFSunlockclose {
my($fh) = @_;

        flock($fh, LOCK_UN);
        close ($fh);


Perl 6 will give you the big knob. -- Larry Wall

------------------------ MailScanner list ------------------------
To unsubscribe, email jiscmail at with the words:
'leave mailscanner' in the body of the email.
Before posting, read the MAQ ( and
the archives (

Support MailScanner development - buy the book off the website!

More information about the MailScanner mailing list