Setting Up SPF and DKIM for an Ubuntu 14.04 Mail Server
It is becoming ever harder these days to ensure that your mail reaches its recipients. Set up a mail server in the cloud that happens to use an IP address that was at some time in the past used by spammers, or engage in a serious discussion of subjects that see a lot of spam, and you can wave goodbye to the certainty of delivery of your mail to addresses at Gmail or other similar email providers. These entities maintain their own arcane anti-spam infrastructures, inscrutable and distinct from the open world of IP address blacklists. Resolving issues or even simply attracting the attention of anyone who might help is essentially impossible if you don't happen to run a large company.
Thus everyone who builds their own mail server should set up the two simple frameworks that email providers pay attention to when it comes to the decision tree for their anti-spam automation: Sender Policy Framework (SPF) and DomainKeys Identified Mail (DKIM). These are not hard to put in place if you have a Postfix mail server on some variant of Linux, and make a big difference. The guide in this post assumes an Ubuntu 14.04 server, set up according to a recipe you'll find elsewhere on this site.
Hopefully it goes without saying, but throughout this post, you should replace example.com with your mail domain.
Sender Policy Framework (SPF)
SPF requires only that you add a TXT record to your DNS zone for the domain. How that happens depends on the tools provided by your domain registrar, or the tools you set up yourself should you manage your own nameservers. If using a registrar's web interface to make DNS changes, you may or may not have the option to enter a subdomain for the record. If you do, then leave that field blank.
This generic SPF TXT record authorizes mail originating from mail servers for your domain that are identified by MX records and all other servers associated with your domain that have A records:
"v=spf1 a mx -all"
Note that the double quotes are a necessary part of the SPF TXT record. Much more complicated records than this are possible, as outlined in the SPF documentation. You can see some of these more complex examples in the wild by using the dig command. e.g.:
dig google.com txt
DomainKeys Identified Mail (DKIM)
Setting up DKIM is a little more involved than SPF, but still not too challenging if you are already running a Postfix mail server on Ubuntu. First install the necessary packages:
apt-get install opendkim opendkim-tools
Add the following to /etc/opendkim.conf:
Domain example.com KeyFile /etc/postfix/dkim.key Selector dkim SOCKET inet:8891@localhost
Add the following to /etc/default/opendkim:
Append a suitable DKIM configuration to /etc/postfix/main.cf:
# DKIM # -------------------------------------- milter_default_action = accept milter_protocol = 2 smtpd_milters = inet:localhost:8891 non_smtpd_milters = inet:localhost:8891
You must append "no_milters" to the "receive_override_options" line in /etc/postfix/master.cf. This prevents multiple signatures being placed on the same outgoing mail item. If you are using the Ubuntu 14.04 setup guide at this site, then that line becomes the following:
Now you can generate a private key for signing outgoing mail. Note that in the following command, "dkim" is the value given to Selector in /etc/opendkim.conf. This can be any simple string, provided you are consistent about replacing "dkim" with your desired value everywhere in this recipe. Run the following command to generate the key and associated materials in the form of two files, dkim.private and dkim.txt. The former is the RSA private key, while the latter contains the entry the you will have to place into your DNS records.
opendkim-genkey -t -s dkim -d example.com
Move the key into place, but don't forget to take a copy and keep that copy backed up somewhere safe:
mv dkim.private /etc/postfix/dkim.key
You'll need to restart Postfix and OpenDKIM services to pick up the configuration changes so that outgoing mail is signed using DKIM:
service opendkim start service postfix restart
Next up is the DNS record setup. How you do this is again completely dependent on how you manage DNS or how it is managed for you - everyone's tools are different. Note that some registrars do not let you create raw TXT records with specific subdomains, which will prevent you from creating DKIM TXT records. If this is the case, then you will have to transfer your domain to a real registrar that lets you play with all the toys.
The file dkim.txt contains the following content, the full TXT record that must be created. It has the subdomain dkim._domainkey and a long set of encoded content as the value. Again "dkim" is the value given to Selector in /etc/opendkim.conf.
dkim._domainkey IN TXT ( "v=DKIM1; k=rsa; t=y; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9rulKo58JIb5h+3MMEnYhlnbuVgRoA4w68R/X7qA2Lfv3RpdrrUb+r7KxemIo6PUIOm6uZ5OymhBgpJ0LAWBHBSJjnFmDXNajSgxMOcvkpgmVCW1/k1kxK864WVVSyFVQPyUImqklY+ws4u+mog3PSbuq2J8NFAnvSwzMg3vT1QIDAQAB" ; ----- DKIM key mail for example.com
When setting this up you should omit the "k=rsa; t=y;" portion of the value. The first item there refers to the key format and that defaults to RSA. They second denotes that this is a test entry, and should not be included. So the value looks like this:
It is helpful to view examples in the wild for the purposes of comparison, so that you can see how you should enter the value into your records. You can use the DKIM key checker or other tools such as dig. Note that the "dkim._domainkey" is the subdomain in the following command:
dig dkim._domainkey.twitter.com txt
Monitor the OpenDKIM Service
If you are using Monit to monitor services, you should add a configuration file /etc/monit/conf.d/opendkim:
check process opendkim with pidfile /var/run/opendkim/opendkim.pid group mail start program = "/etc/init.d/opendkim start" stop program = "/etc/init.d/opendkim stop" if 5 restarts within 5 cycles then timeout
Then restart Monit:
service monit restart
Sharing a DKIM Key for Multiple Domains
If you are serving multiple domains from the same mail server, then the contents of /etc/opendkim.conf should be:
Domain * KeyFile /etc/postfix/dkim.key Selector dkim SOCKET inet:8891@localhost
This will work unless you are running a mailing list or similar, in which outgoing mail has From headers containing addresses in domains other than the list domain. In that case you might look at a helpful ServerFault question and answer for more complex configurations that can support that scenario.
Testing the New Additions
A decent testing service is Mail Tester. Give the DNS changes a chance to propagate before using it.