SPF “too many DNS lookups”: what causes permerror, and how to fix it
An SPF record is allowed ten DNS lookups. That
count includes every lookup performed inside the records you reference with
include:, and inside the records those reference. Go over
the limit and receiving mail servers return permerror and treat
your domain as though it has no SPF record at all — while the
record itself still looks completely valid.
Why this failure is so easy to miss
Most SPF validators check the syntax of the record in front of them. The lookup limit isn't a syntax problem — the record is perfectly well-formed. The cost is hidden inside the providers you reference.
Adding one SaaS vendor to your SPF looks like adding one term. But
include:_spf.google.com is not one lookup: Google's record itself
contains further include: terms, each of which costs another. A
single vendor can consume three or four of your ten.
Which terms count toward the limit
RFC 7208 §4.6.4 counts the terms that require a DNS query. Address mechanisms are free, because they need no lookup:
| Costs a lookup | Free |
|---|---|
include:, a, mx,
ptr, exists:, redirect= |
ip4:, ip6:, all |
Two further rules catch people out. The limit is on lookups performed, not terms written — so a nested chain three levels deep still spends from the same budget of ten. And more than two void lookups (queries returning no record) is itself a permerror, independent of the count.
A record that fails
v=spf1 include:_spf.google.com include:spf.protection.outlook.com
include:sendgrid.net include:mail.zendesk.com
include:_spf.salesforce.com include:servers.mcsv.net -all
Six include: terms — but each expands. Google alone typically
adds three or four. This record resolves to well over ten and returns
permerror, so every message it was meant to authorise fails SPF.
How to fix it
1. Remove senders you no longer use
The cheapest fix, and usually available. SPF records accumulate vendors
long after the vendor is gone. Every removed include: frees its
entire nested cost, not just one lookup.
2. Flatten stable includes to IP ranges
Replace an include: with the ip4: and
ip6: ranges it resolves to. Those cost nothing. The trade-off is
real and worth stating plainly: if the provider changes their sending
IPs, your SPF silently stops authorising them. Only flatten providers
who publish stable ranges, and re-check periodically.
3. Use subdomains for bulk senders
Send marketing mail from news.yourdomain.com with its own SPF
record and its own budget of ten. This is the structurally correct fix rather
than a workaround — it also isolates your transactional mail's reputation from
your marketing reputation.
4. Drop ptr entirely
RFC 7208 deprecates it, some receivers ignore it, and it costs a lookup.
Related failures worth checking at the same time
- Multiple SPF records. Publishing two is an immediate permerror; receivers discard SPF entirely.
- Ending in
+all. Authorises the entire internet to send as your domain — worse than having no SPF. - DMARC with no
rua=. Without aggregate reports you have no way to see authentication failing.
The checker above reports all of these, along with DKIM, MTA-STS, TLS-RPT and DNSSEC. There is also an API if you need to check domains programmatically.