Common errors in SPF records

The other day I was asked to come up with some common errors that we see when people set up SPF records as we want to start notifying our customers when they have these types of errors. I thought it would be a good idea to make this public and add to it as necessary.

1. You have too many DNS lookups

SPF specifies a maximum number of 10 DNS lookups (e.g., nested includes, A-record resolution, MX-record resolution, PTR record resolution, etc. are greater than 10). I talk about how to get around this here:

https://blogs.msdn.com/b/tzink/archive/2016/01/22/email-authentication-should-work-out-of-the-box-and-we-should-not-rely-upon-domain-owners-to-do-it-themselves.aspx

Most verifiers, if they can verify you before hitting the 10 DNS lookup limit, will pass if you haven’t hit 10 up to that point. But go over and this will generate a PermError.

2. Too many SPF records in DNS

This occurs when someone meant to add more IPs or 3rd parties to their SPF record and created a second TXT record instead of including them all into the first one:

contoso.com IN TXT "v=spf1 include:spf.protection.outlook.com –all"
contoso.com IN TXT "v=spf1 ip4:1.2.3.4 –all"

Whereas it should be this:

contoso.com IN TXT "v=spf1 include:spf.protection.outlook.com ip4:1.2.3.4 –all"

If this occurs, SPF should return a PermError. We here at Office 365 will cut you some slack and interpret two SPF records as a single one; that is, we detect your probable intent even though you didn’t do it correctly. Most other receivers are not nearly as forgiving.

3. Duplication of what you need for Office 365 to work

You only need to have include:spf.protection.outlook.com in your SPF record, you don’t need any of the following:

include:outlook.com
include:spf.messaging.microsoft.com
include:spf.frontbridge.com

While SPF still works if you include any of the others, you will get unnecessarily closer to the 10 DNS lookup limit (this prevents you from adding much more 3rd party services to send on your behalf).

As a matter of fact, if you have any of those in your SPF record, you should replace them with include:spf.protection.outlook.com.

4. Forgetting to include an ip4: and instead putting ip:

For example:

contoso.com IN TXT "v=spf1 ip4:1.2.3.4 ip4:5.6.7.8 ip:9.10.11.12 –all"

Office 365 will cut you some slack and interpret an ip: as ip4:. Other services aren’t quite so forgiving and may generate a PermError.

5. Not properly formatting the double quotes

You can put additional double quotes into the SPF record as long as you put spaces in the correct places:

contoso.com IN TXT "v=spf1" "include:spf.protection.outlook.com" "ip4:1.2.3.4" "include:_spf.google.com" "–all"

The above is created by someone who is trying to add additional 3rd parties to their SPF record by putting them in double quotes. However, this concatenates the record so it gets treated as this:

contoso.com IN TXT "v=spf1include:spf.protection.outlook.comip4:1.2.3.4include:_spf.google.com–all"

Email receivers will treat this as you not having an SPF record at all.

It should be this (better to not include any quotes at all because you are using up characters in your SPF record, and you only have 255 to spend):

contoso.com IN TXT "v=spf1" " include:spf.protection.outlook.com" " ip4:1.2.3.4" " include:_spf.google.com" " –all"

6. Exceeding 255 characters in an SPF record

If you are going over 255 characters, it should be separated by a space and max of two components:

contoso.com IN TXT "v=spf1 include:spf.protection.outlook.com <bunch of others> ip4:1.2.3.4 " "ip4:5.6.7.8 –all"

If you go over 255 characters, I think most receivers will return a PermError but it varies by receiver.

7. Forgetting to include key parts of the record indicating that it is an SPF record

These are all incorrect:

contoso.com IN TXT "include:spf.protection.outlook.com ip4:1.2.3.4 –all"
contoso.com IN TXT "v=spf1 include:spf.protection.outlook.com ip4:1.2.3.4"
contoso.com IN TXT "include:spf.protection.outlook.com ip4:1.2.3.4"

The first one lacks v=spf1, the second does not have a failure policy, and the last one lacks both.

If you do this, most receivers will either return a PermError or will treat it as if there is no SPF record.

8. Having a failure policy of +all

It’s okay to have any of the following policies: -all, ~all, ?all. Don’t do +all:

contoso.com IN TXT "v=spf1 ip4:1.2.3.4 +all"

This allows the entire world to send email as you. I was talking to another (very) large receiver at M3AAWG this past week and we’re talking about tightening up this behavior by rejecting in SMTP if you have a +all in your SPF record.

So don’t do it.

9. Having large IP ranges in your SPF record

IP ranges larger than /16 usually are wider than you need:

contoso.com IN TXT "v=spf1 ip4:1.0.0.0/2 –all"

That allows far too many IPs to send on your behalf. This is another pattern that I was talking about with the large receiver at M3AAWG that we are looking to start rejecting in SMTP.

10. Including a PTR in your SPF record

This one… I am not so strict about:

contoso.com IN TXT "v=spf1 ptr ptr:contoso.com –all"

The SPF spec says not to do this and it is deprecated, but I can see the rationale for still using it. So while I recommend not to use it, I’m not so sure I’d want to reject on it.


Those are the most common errors that we see today, and how they are treated. As I think of or discover more, I will add to the list.

To test SPF records, I use the following two websites:

SPF Record Testing Tools:
https://www.kitterman.com/spf/validate.html

DMARCIAN’s SPF Surveyer
https://dmarcian.com/spf-survey/

Other than some Perl and shell scripts I wrote internally, that’s all I basically use.