A short primer on SPF, DKIM and DMARC
I use FastMail for my email and as I control my own domain, I needed to set up SFP, DKIM and DMARC on it. These are DNS records that help the email servers put the emails that I send into my recipient’s inbox and to mark any forged emails as spam. These are my tidied up notes so that I can find them again when I next need them.
SPF
SPF is a DNS record that provides a list of mail servers that are allowed send email from this domain. I use Fastmail, so akrabat.com’s SPF record is:
$ dig domain akrabat.com txt +short "v=spf1 include:spf.messagingengine.com -all"
This states that spf.messagingengine.com is the only valid mail server for mail from akrabat.com as the ~all means “no other server ever sends email for this domain”. You have a choice between -all and ~all, where -all is a hard-failure and the email is rejected and ~all is a soft-failure where the email is accepted but marked. If there isn’t -all or ~all at the end, then the SPF record essentially does nothing. Reading around, ~all is recommended by Freddie Leeman, EasyDMARC and others.
If I was using mailing list software to send emails, I’d add an additional include: section to the SPF record.
DKIM
With DKIM the mail server signs the mail with a private keys and signs the hash of the email’s body and key headers with it. It provides the DKIM header with this information along with information on where to find the public key.
The public key is in a DNS record for the domain. Usually there’s more than one and are registered as subdomains of the _domainkey subdomain of the domain from which the email is from.
For Fastmail, these are CNAME records to their servers:
fm1._domainkey.akrabat.com CNAME fm1.akrabat.com.dkim.fmhosted.com. fm2._domainkey.akrabat.com CNAME fm2.akrabat.com.dkim.fmhosted.com. fm3._domainkey.akrabat.com CNAME fm3.akrabat.com.dkim.fmhosted.com.
Fastmail can then control the public keys and rotates them as required, with at least one of the three having a valid key set.
As of this moment, this is fm2:
$ dig domain fm2._domainkey.akrabat.com txt +short fm2.akrabat.com.dkim.fmhosted.com. "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA49GNR9SRZS9ltJ19mO3a+lZ16v+Px3d9ZG3Q6s3vcS/M0iEDclHc45mE0lswO981plnNjazEqV3L8fqbUbc2P3ZSTenY/6apMH5lCjGkBaln+j9GMOHVJIkNpfPckssNE70GBMiHxUy42yClyVH0BD/inqqFY5Wq0N92EPipCWtpiJ0E9SKRVlQazvLxaeGX2" "3+WEyyIgp15F5rujcFg8nz1K0UJPpsSz+LptzkcEV03v92+pVI6D1GR2l/24cGCtV4SNjD1ASAqjs0OzYUGEmiJflsUPpTZQrDeihrw+fSPcaMbRBJzLMe2huens5WqZYcCd58Nn1AOQFOBwCmAmwIDAQAB"
The k field is the key type and p is the key itself.
When an email is received, the receiving mail server will read the DKIM header in the mail, look up the correct key and then compute the signature and compare to the one provided. If they match, then the mail has been sent from the correct server. If it doesn’t match, then it’s a forged email. The email signature will fail if the public key is wrong or the email has been tampered with, so it’s also an integrity check.
DMARC
An interesting thing about SPF and DKIM is that even if an email fails both checks (i.e. is forged), it’s most likely to end up in the recipient’s inbox. This is less than ideal.
The DMARC record is used to indicate the policy that the receiving email server should apply to emails that fail the SPF and DKIM checks.
This is a TXT record held on the _dmarc subdomain. This is mine:
$ dig domain _dmarc.akrabat.com txt +short "v=DMARC1;p=quarantine;pct=100;rua=mailto:dmarc@akrabat.com;ruf=mailto:dmarc@akrabat.com"
The p parameter is the policy which can be none, quarantine or reject. These are in order of strictness, where none does nothing, quarantine marks it as spam and reject rejects the email so that the recipient never sees it.
The pct parameter is the percentage of emails from the domain that the receiving server should apply this policy to. I have no idea why you would set it to anything less than 100.
When an email server reads the DMARC record, it will send failure reports to the email addresses listed in the rua and ruf parameters. These are XML files and while humans can read XML, it’s better to let computers do it! Something like parsedmarc does this and there are many others.
I started with a policy of none and watched the reports that I received. With everything set up correctly, all the reports received were for forged emails and there were none are for valid emails. At which point I upped the policy to quarantine, and could probably move to reject now, but I’m not quite brave enough!
Reference
I can’t recommend I figured out how DMARC works, and it almost broke me by Simon Andrews enough for a readable article on all this.
For tools to check the various records, mimecast has a set:
- SPF checker: https://www.mimecast.com/products/dmarc-analyzer/spf-record-check/
- DKIM checker: https://www.mimecast.com/products/dmarc-analyzer/dkim-check/
- DMARC inspector: https://www.mimecast.com/products/dmarc-analyzer/dmarc-check/
In addition, aboutmy.email will analyse an email you send to it which can be helpful to check that it’s all set up as you think. Note that this service is biased towards sending bulk emails though, so reports non-compliance with things that aren’t necessary for sending normal email.
See also, Andreas Heigl’s experience with outlook.com when self-hosting an email server.