Checking SPF on incoming mail with Postfix

Something I’ve been wanting to add to my mail server for a while is Sender Policy Framework (SPF) checking on incoming mail. For anyone who isn’t familiar with SPF, it enables the owner of a domain to specify which hosts are allowed to send mail for that domain by adding a TXT record. Other mail servers can lookup this record via DNS and accept or reject incoming mail depending on whether the mail comes from an authorised host. SPF isn’t perfect, and there are a few known issues, but it is one of a collection of tools that a sysadmin can deploy to reduce incoming spam.

I use Postfix on all my mail servers and fortunately a lot of the work has been done by other people. On Debian you can add SPF checking on incoming mail in four steps (these should work for Ubuntu as well).

Step 1: Install the postfix-policyd-spf-python package.

Step 2: Add the following line to /etc/postfix/master.cf

policy-spf  unix  -       n       n       -       -       spawn
  user=nobody argv=/usr/bin/policyd-spf

Step 3: Add the following line to /etc/postfix/main.cf

policy-spf_time_limit = 3600s

This timeout allows for a DNS lookup of the SPF record.

Step 4: Add the following line to smtpd_relay_restrictions as the last option before the final permit

check_policy_service unix:private/policy-spf

The reason for leaving the SPF check until last is that it involves a DNS lookup, which is a relatively expensive operation compared to other checks such as reject_unauth_destination.

To check whether SPF is configured correctly, search your mail log for policyd-spf. Messages which are rejected due to an SPF failure will look like this:

Jan 19 11:55:58 davros policyd-spf[23964]: Fail; identity=mailfrom; client-ip=192.0.2.1; helo=myhost; envelope-from=test@example.net; receiver=test@example.org

Jan 19 11:55:58 davros postfix/smtpd[23957]: NOQUEUE: reject: RCPT from unknown[192.0.2.1]: 550 5.7.1 <test@example.org>: Recipient address rejected: Message rejected due to: SPF fail - not authorized. Please see http://www.openspf.net/Why?s=mfrom;id=test@example.net;ip=192.0.2.1;r=test@example.org; from=<test_example.net> to=<test@example.org> proto=ESMTP helo=