Exim4 Greylisting using PHP and MySQL


You may have gathered that I do a little bit of PHP coding every once in a while, sometimes I even code something useful!

Greylisting is a fairly effective method of stopping spam-bots (infected machines), which usually use a send and forget method of delivery, from sending email to you by initiallt rejecting the message with a 451 (temporary local failure) error code. Spam-bots will usually not retry, wheras a properly configure mailserver will typically attempt redelivery within a few minutes.

Wheras I appreciate that there are a lot of solutions out there that facilitate greylisting, this simple bit of code will allow you to implement greylisting on an exim4 server.

Clearly you will need:

  • exim4
  • php
  • mysql

Database Schema:

create table data (
    `date` BIGINT NOT NULL DEFAULT 0,
    `token` CHAR(32) NOT NULL DEFAULT '',
    PRIMARY KEY (`token`), KEY(`date`)
);

PHP Code:

#!/usr/local/bin/php
<?PHP
mysql_connect('localhost', 'username', 'password');
mysql_select_db('database');
$token = md5($argv[1].$argv[2]);

$res = mysql_query("SELECT * FROM `data` WHERE `token` = '".$token."'");
if ($row = @mysql_fetch_array($res)) {
        if ($row['date'] < date('U')) {
                echo "no";
                die();
        }
        else
        {
                echo "yes";
                die();
        }

} else {
        mysql_query("INSERT INTO `data` (`date`,`token`) 
                     VALUES ('".(date('U')+15)."', '".$token."')");
        echo "yes";
        die();
}
die('yes');
?>

You will also need to add the following ACL to your exim config file (typically /etc/exim4/exim4.conf.template) immediately below acl_smtp_rcpt :

defer
    message = greylisted
    log_message = greylisted ${lc:$local_part}@${lc:$domain}
    !authenticated = *
    !senders       = :
    !hosts         = :
    condition = ${run {/etc/exim4/greylist.php \\
${lc:$local_part}@${lc:$domain} ${lc:$sender_address}}{$value}{$value}}

This is, of course, assuming that you put the PHP code into the file greylist.php in /etc/exim4/.

That's all there is to it. Create the database, drop in the php file, configure the MySQL username/password/database, drop in the ACL and restart exim.

If you have any problems getting this working, please email me at Email Me!†and I will help you set it up as best I can.

3 Responses to “Exim4 Greylisting using PHP and MySQL”

  1. Adam Says:

    An interesting theory, I must say. I saw another suggestion made the other week by a fellow developer, which was to use a text field that is styled to blend into the background, that way when a bot fills in the details on the website, it fills in every single field. Whereas a normal user would not be able to see the blended field and thus leave it blank. If the field contains blank, you would cancel the registration process, or at least then proving a CAPTCHA image for verification just in case the user is using a web browser that is too old to support CSS.

    The advantage of that is CAPTCHA can often scare away users if they get it wrong the first time round. Many will in fact navigate away from the browser and you’ve lost yourself a member.

  2. Gus Says:

    I found Adam’s comment to be quite interesting as well – that’s a very good idea for preventing automated registrations!

    Andy – I was wondering why you embedded your email address as an image, given that you are just singing the praises of a greylisting system for your MTA… ;-)

  3. Andy Says:

    Greylisting works, period.

    However, I don’t really want to make the spammer’s job any easier than it needs to be.

Leave a Reply