SPF explained, and the 10-lookup limit
How SPF works, why records quietly break as clients add new services, and how to fix a record with too many DNS lookups.
By Doug Hall · Published · Updated
- SPF is a TXT record listing the servers allowed to send email for a domain.
- Receivers may only do 10 DNS lookups while checking it. Go over and SPF fails for every message.
- Remove old services first; flattening includes into IP ranges is the fallback, and must be kept up to date.
This guide is for agencies and IT providers who manage SPF records for clients, and keep finding that a record which worked last year has quietly stopped. It explains how SPF works, the two lookup limits in the standard, how to repair a record that's over them, and which all to end with once DMARC is in place.
What SPF does
SPF (Sender Policy Framework, RFC 7208) lets a domain publish the list of servers allowed to send its email. A receiving server looks up the list and checks the sending server is on it. On its own that only protects the envelope sender, an address people rarely see, which is why SPF matters most as one half of DMARC.
Reading an SPF record
v=spf1 include:spf.protection.outlook.com include:servers.mcsv.net ip4:203.0.113.10 -all
- v=spf1
- Marks the record as SPF. There must be exactly one per domain.
- include:
- Adds another domain's SPF list, usually a service such as Microsoft 365 or Mailchimp.
- ip4: ip6:
- Allows an address or range directly.
- a mx
- Allows the domain's own web or mail server addresses.
- -all
- Everything not listed fails. ~all marks it as suspicious instead; which to use is covered below.
The 10-lookup limit
To stop SPF being used to flood DNS servers, the standard (RFC 7208 section 4.6.4) limits a check to 10 DNS lookups. Every include, a, mx, ptr, exists and redirect counts, including the ones inside each included record. Go over and the result is a permanent error: SPF fails for every message, genuine or not.
It creeps up unnoticed. Each service's include can use several lookups of its own, so add a newsletter tool, a helpdesk, an invoicing system and a CRM, and a record that worked last year quietly breaks.
The same section sets a second limit that fewer people know about: at most two void lookups, meaning mechanisms whose name doesn't exist or returns no records. A third is a permanent error as well. Includes for services the client cancelled years ago are the usual cause, and the fix is simply to remove them; see fixing SPF void lookups.
SPF PermError: too many DNS lookups
That's the wording most tools and bounce messages use when a record goes over the limit. You may also see it in a message's headers as spf=permerror, and in DMARC reports as an SPF result of permerror. It means the record itself is broken, not that one server is missing from it, so every message fails SPF until the record is fixed. Our SPF checker counts the lookups include by include, so you can see which service is costing the most, and the fix page walks through the repair step by step.
Fixing a record that's over the limit
- Remove services the client no longer uses. Old includes are the most common cause.
- Drop ptr, which is deprecated, and replace
aormxwith theip4addresses they point at, if those rarely change. - Move bulk mail to a subdomain, such as news.example.co.uk, with its own SPF record. Many newsletter tools support this, and it keeps marketing mail from affecting the main domain's reputation.
- Rely on DKIM where a service signs with the domain's own key: DMARC passes on DKIM alone, so that service may not need to be in SPF at all.
SPF flattening
Flattening replaces includes with the IP ranges they currently resolve to, so they no longer cost lookups. The catch: providers change their ranges without notice, and a flattened record that isn't refreshed starts failing genuine mail. Only flatten with something that re-checks automatically. Hosted SPF in Domain Health Hub re-resolves every 6 hours and keeps the last good record if a lookup fails.
~all or -all?
Use ~all while you're still confirming every sender is listed. Never use +all, which allows the whole internet to send as the domain, and avoid ?all, which tells receivers to ignore the result.
Once DMARC is enforcing, the choice between ~all and -all is less obvious than it looks. SPF is checked during the SMTP conversation, before DMARC runs, and RFC 7208 section 8.4 allows a receiver to refuse a message on an SPF fail at that point. RFC 7489 section 10.1, and its replacement RFC 9989 section 7.1, spell out the consequence: a message rejected at that stage never reaches the DMARC check, so it never appears in the aggregate reports. Forwarded mail is the usual casualty. It fails SPF because the forwarder isn't in the record, but it would still pass DMARC on its aligned DKIM signature. With -all, some receivers refuse it before DMARC gets a say, and the reports give you no clue it happened.
So for a domain that sends mail, once DMARC is at quarantine or reject and every sender signs with aligned DKIM, ~all is usually the safer ending, and DMARC does the enforcing. -all belongs on domains that never send at all, alongside p=reject; see protecting parked domains.
Doing this for clients? Domain Health Hub checks every client domain each day and puts the results in a monthly report card with your logo. Start a free trial; no card needed.
Questions
Can a domain have two SPF records?
No. Two records starting v=spf1 make SPF fail with a permanent error. Merge them into one.
Is SPF enough on its own?
No. SPF checks the hidden envelope sender, not the From address people see, and it breaks when mail is forwarded. Use it with DKIM and DMARC.
Do ip4 and ip6 count towards the limit?
No. Only mechanisms that need a DNS lookup count: include, a, mx, ptr, exists and the redirect modifier.
Watch every client's domains, every day.
Reports read for you, and a monthly report card your clients will understand.