Sender Policy Framework, or SPF, is a really simple mechanism that allows you to stop others being able to send spoofed emails from your domain. To enable SPF all you have to do is create a DNS record with the appropriate information.


SPF

You can read the RFC for SPF if you like, but it's pretty heavy reading and I'm going to condense down all of the information you need in this blog. Essentially, SPF will allow you to stop people spoofing your domain by advertising the hosts that are allowed to send emails from your domain for a receiving party to check. If you receive an email claiming to be from scotthelme.co.uk but the host that sent it isn't listed in my SPF policy, your email provider/server will know that it didn't really come from me. You can now stop people sending emails that look like they came from you when they didn't. That's a pretty important feature and fortunately, it's really easy to setup.


A simple DNS record

That's literally all there is to SPF, a simple DNS TXT record. Here's mine:


v=spf1 include:spf.messagingengine.com -all

Knowing what to put in this DNS record is the trick though so let's look at how you create your own. The first thing that an SPF record must contain is the version string, v=spf1. Without this, your policy will be ignored.


v=spf1

Technically we have a valid SPF record here, but it's not going to do much because we haven't defined any 'mechanisms'.


Mechanisms

Mechanisms are used to list the hosts that are allowed to send emails from our domain and can include the following from Section 5 of the RFC. You can have one or more of these in your policy. When somebody receives an email that claims to be from your domain, the receiving party can check the source IP of the email against your SPF record for a match.


all | include | a | mx | ptr | ip4 | ip6 | exists

Some of these are fairly self explanatory but I will quickly go over them.


all

This mechanism always matches so should only be used as the rightmost mechanism in a policy as the mechanisms are evaluated left to right. As a result, anything after an 'all' mechanism will never be used. This means the email could have could from any IP and the receiver should accept it.


include

The include mechanism allows you to delegate control of your SPF record to another party, as you can see in my example above. I'm using include:spf.messagingengine.com because I use FastMail, which tells the person making the query to go and check the other domain for the policy instead of my domain.


a

The a mechanism provides a host name that the receiving party should perform a DNS lookup on. They then check the IP address, or addresses, returned by the DNS query and if the source IP of the email matches one of these, it can be accepted.


mx

An MX mechanism instructs the receiving party to lookup the MX records for the domain in question and then perform a DNS lookup on those for their A records. It is then subject to the same processing as the A mechanism above.


ptr

A DNS PTR record is the opposite of an A record. With an A record you provide the domain name and get an IP, with a PTR record you provide the IP and get a domain name. The PTR mechanism allows you to specify the IP that the receiving party should perform a reverse DNS lookup on and fetch the domain name. They then do a DNS lookup on the domain name and make sure they get the same IP back. If they do, the rule matches and they can accept the email.


ip4 | ip6

These mechanisms specify an IP network that the source IP for the email must fall within. You can use ip4-cidr-length, ip6-cidr-length or dual-cidr-length to specify the network length, which if omitted is assumed to be /32 for IPv4 or /128 for IPv6.


exists

This mechanism gets a little complicated but allows you to construct an arbitrary domain name the receiving party must perform a DNS lookup on. SPF allows you to create macros for custom and complex rules that most of us probably don't/won't need. As an example, I could specify exists:%{i}.scotthelme.co.uk and the %{i} instructs the receiving mail server to substitute this element with the IP address of the person who sent the email, to form something like 87.112.151.125.scotthelme.co.uk. The receiving party then does a DNS lookup on this domain and I can control whether or not the record exists. The only difference here is that for this test the record only needs to exist, the returned IP address does not need to match that of the sender.


Qualifiers

To allow for some better fine tuning we have a set of 4 qualifiers to modify the mechanisms we use.


+ | - | ~ | ?

The default qualifier if none are specified on a mechanism is + and they have the following functions.


+

This is the default qualifier and instructs the receiving party that the result of the check should 'Pass' if the rule matches. For example, if we specify v=spf1 +a as our SPF record, the receiving party will perform a DNS lookup on the domain and if any IP address returned matches the source IP of the email, then it should pass processing and be accepted.


-

This negates the mechanism and instructs the receiving party that the result of the check should 'Fail' if the rule matches. A common example of this qualifier in use would be v=spf1 +a -all. We're instructing the receiving party to accept the email if the source IP matches one of our A records, but to reject it if it matches any other IP address.


~

This is the 'Soft Fail' qualifier and means that the test is inconclusive. In this scenario the receiving party can accept the mail but perhaps mark it as spam.


?

The 'Neutral' qualifier indicates that no information can be provided to the receiving party and they should accept the mail.


Modifiers

The last little bit to add (don't worry, there's not much more!) are the 2 modifiers we have available to us.


redirect | exp

Modifiers are optional and can only be used once per policy, unlike the mechanisms above which can be specified multiple times if required. Any unknown modifiers will be ignored.


redirect

This modifier allows you to specify a domain that the SPF lookup should be 'redirected' to. This is essentially a way to hand over full control of your SPF record to another domain. If you send email from multiple subdomains, say london|newyork|sydney.example.com, then each of these domains could return an SPF record with v=spf1 redirect=spf.example.com so that SPF records can be managed centrally by example.com instead. The value of redirect can also be macro enabled like the exists mechanism above.


exp

The explanation modifier allows you to provide a custom error string that the receiving party should return to the sender when they reject an email. The value should contain a domain and the receiving party will perform a TXT lookup against that domain, macro expand the returned value if necessary and return it to the sender.


There's an easier way

SPF itself isn't too complicated a mechanism and can offer us a reasonable level of protection. The reality is though it's probably much easier than understanding the above if you use a mail provider like I do. I use FastMail to provide my email services so they do all of the configuration and worrying and simply provide me with the policy I need to use!


spf for scotthelme.co.uk


In my account settings there is a status page that informs me SPF is not configured and the appropriate policy to set. Copy and paste the provided string into a DNS TXT record and voila, SPF is configured! It's a similar story if you use Google, you can find their advised configuration if you use Google Apps right here.


google SPF


Microsoft also have a handy table here for helping you determine the SPF policy you need.


Check SPF

SPF is a really easy protection to put in place and offers us a good amount of protection in return. If you want to check if you have SPF deployed, or any other site for that matter, you can use the Google Apps Toolbox to easily check your DNS TXT records, check mine here.


dns txt record