Home > Support > HOWTO List > Greylisting with postgrey and Postfix

Greylisting

Greylisting has proven to be a pretty effective method for reducing the amount of spam you receive.  It works by temporarily rejecting emails.  Valid email servers will then retry delivery, and be allowed through while spammers will (hopefully) give up.  See http://www.greylisting.org/ for more info.

The postgrey application at http://postgrey.schweikert.ch/ provides a simple way to implement greylisting for postfix mail servers.

Greylisting would have saved Peter in Samoa

Recently Peter here at RimuHosting went to Samoa for a week (nice for some).  He found himself on a 9600 baud internet connection.  And there was no way it was keeping up with the 200-odd spam emails that arrived in his inbox each day.  After implementing greylisting the spam has dropped down to less than a dozen or so a day.

Installing postgrey

Debian and Ubuntu have the package available in the main repositories.  On CentOS/RHEL based distros, you will need to enable the rpmforge repository per http://rimuhosting.com/knowledgebase/linux/distros/centos/extra-packages-for-rhel4-and-centos5

Then just install postgrey with apt

apt-get install postgrey

Configure postgrey to start at boot:

Debian/Ubuntu:

update-rc.d postgrey defaults

CentOS/RHEL:

chkconfig postgrey on

And tell it to start up (any distro):

/etc/init.d/postgrey start

Now, tell postfix to use it:

Debian/Ubuntu:
The package listens on localhost:10023 by default, so edit /etc/postfix/main.cf, and add 'check_policy_service inet:127.0.0.1:10023' to smtpd_recipient_restrictions.  Make sure to add it after permit_sasl_authenticated so you don't greylist authenticated users.  Like this:


smtpd_recipient_restrictions =
        permit_mynetworks
        permit_sasl_authenticated
        reject_unauth_destination
        check_policy_service inet:127.0.0.1:10023

CentOS/RHEL:
This package listens on a unix socket by default, so edit /etc/postfix/main.cf and add 'check_policy_service unix:/var/spool/postfix/postgrey/socket' to 'smtpd_recipient_restrictions.  Again, make sure to add it after permit_sasl_authenticated so as not to greylist yourself.  Example:


smtpd_recipient_restrictions =
        permit_mynetworks
        permit_sasl_authenticated
        reject_unauth_destination
        check_policy_service unix:/var/spool/postfix/postgrey/socket

Per-user greylisting

You can set it so that only particular users have their emails grey-listed.  e.g. in /etc/postfix/main.cf have:


smtpd_restriction_classes = greylist
greylist = check_policy_service inet:127.0.0.1:10023 

And add the following to smtpd_recipient_restrictions in /etc/postfix/main.cf:

    smtpd_recipient_restrictions =
            [other options that normally go here]
            check_recipient_access hash:/etc/postfix/greylist_optin 

(Note that you would have this set in smtpd_recipient_restrictions instead of the "check_policy_service unix:/var/spool/postfix/postgrey/socket" setting mentioned in the previous section.

In /etc/postfix/greylist_optin put users who should be greylisted followed by 'greylist' (the class defined above):


fred@example.com    greylist
mary@example.com     greylist

Sending mail to those users should now get greylisted (might need to 'postmap /etc/postfix/greylist_optin' before restarting postfix).

In /etc/postgrey/whitelist_clients you can add domains (domain names, one per line) that you think should not be greylisted.  e.g. domains of users that you deal with frequently (maybe avoiding common sources of spam though like yahoo.com, hotmail.com, etc).

Whitelisting common ESPs

The following script will pull ranges from spf records publish at common ESPs

#!/bin/bash

ESPs="google.com amazonses.com hotmail.com facebook.com twitter.com spamhero.com"

VERBOSE='n'

function parsespf(){
    SPF=$(dig TXT $1 +short | grep 'v=spf1' | sed 's~" "~~g' | tr -d '"')
    [ "$VERBOSE" = "y" ] && echo "#### SPF: $SPF"
    
    for p in $SPF; do
        echo $p | grep -q '^v=spf1\|^~all\|^-all\|^?all' && continue
        if echo $p | grep -q '^ip4:'; then
             [ "$VERBOSE" = "y" ] &&  echo "$(echo $p | sed 's/^ip4://g')    #SPF:$1"
             [ "$VERBOSE" = "n" ] &&  echo "$(echo $p | sed 's/^ip4://g')"
        fi
        if echo $p | grep -q '^include:\|redirect='; then
            [ "$VERBOSE" = "y" ] && echo "#### recursing include or redirect: $p"
            parsespf $(echo $p | sed -e 's/^include://g' -e 's/^redirect=//g')
        fi
    done

}


# We parse the spfs and add them as uniq entries
for e in $ESPs; do
    parsespf $e
done | sort -n | uniq

This script can be used to add a list of ips to postgrey as follows:

 
./whitelistclients.sh >>/etc/postgrey/whitelist_clients