Fixing SPF 'Too Many DNS Lookups' (permerror)
Diagnose and fix SPF permerror caused by exceeding the 10 DNS-lookup limit via flattening.
If a recipient's logs show Received-SPF: permerror or the message "too many DNS lookups", it means that evaluating your SPF record required more DNS lookups than the limit of 10 set by RFC 7208. When this happens the receiving server treats the SPF result as a permanent error it cannot trust, and even legitimate mail can fail authentication as a result.
The tricky part is that the limit counts every nested include too. Your record may look short with just one or two include mechanisms, but if each of those points to a record containing more includes, the real total blows past 10 quickly. The fastest path is to first measure where you stand with the SPF lookup counter, then trim from there using the steps below.
What the 10-lookup limit is and why it exists
SPF reads your v=spf1 record to decide whether the sending IP is authorized. Some mechanisms need extra DNS queries to make that decision. RFC 7208 §4.6.4 caps the total number of lookup-causing mechanisms at 10. Without that cap, a malicious or misconfigured SPF record could force the receiver to perform dozens or hundreds of DNS queries, turning SPF into a DNS amplification vector.
The key nuance: the 10 counts the number of mechanisms that trigger a lookup, not the raw query count. One include:example.com costs 1, and if the record it points to contains its own include, a, or mx, those draw from the same budget of 10. Separately, mx and ptr can produce extra queries when they return many hosts — if an MX returns more than 10 hosts, that alone is a permerror.
Which mechanisms count (comparison)
Knowing exactly what does and does not draw from the budget is the heart of the diagnosis. Here is the breakdown.
| Mechanism / modifier | Counts toward 10? | Notes |
|---|---|---|
include | Yes (most common cause) | Lookups inside the referenced record are summed recursively |
a | Yes | Resolves the domain's A/AAAA records |
mx | Yes | 1 MX query plus one per returned host (over 10 hosts is an immediate permerror) |
ptr | Yes (avoid using) | Slow and unreliable; RFC recommends against it |
exists | Yes | One macro-based A lookup |
redirect= | Yes | Evaluation moves to the target record and its lookups are added |
ip4 / ip6 | No | IP is written inline, no DNS needed (the basis of flattening) |
all | No | Terminator like -all/~all, no lookup |
How to count your own domain
Counting by hand means walking the record line by line and expanding every nested include — and provider records change often, so manual counts drift fast. The reliable approach is to let the SPF lookup counter expand all nested includes and return the total. If you want to see the raw published record first, check it with the SPF lookup tool.
Worked example: hitting 11 and getting permerror
Here is how a record that looks short can cross the limit. Say your domain publishes:
v=spf1 include:_spf.google.com include:spf.protection.outlook.com include:sendgrid.net include:mailgun.org a mx -all
include:_spf.google.com= 1, with 3 more includes inside → +3 (subtotal 4)include:spf.protection.outlook.com= 1, with 1 include inside → +1 (subtotal 6)include:sendgrid.net= 1 (subtotal 7)include:mailgun.org= 1 (subtotal 8)a= 1 (subtotal 9)mx= 1 (subtotal 10)
That is exactly 10 so far — but if the Google include nests one more include (as it sometimes does), the total becomes 11 and you get a permerror. This is a common real-world story: reports of "SPF broke one day and we changed nothing" are usually because a provider grew the records inside its own include.
Three ways to get under the limit
- Remove unused includes. It is very common to find leftover includes for marketing or transactional services you cancelled long ago. Delete any provider you no longer actually send mail through — this is the lowest-risk way to recover headroom.
- SPF flattening. Resolve the IP ranges an include ultimately points to and write them directly as
ip4:/ip6:. Becauseip4/ip6trigger no lookups, they cost nothing against the budget of 10. The trade-off is that if the provider changes its IPs you must update your record yourself, so flattening fits stable, self-managed infrastructure best. - Consolidate senders. If multiple providers do the same job, merge them, and split sending responsibilities across subdomains (for example, marketing on
m.example.com) so the include count is spread out. Each domain gets its own independent budget of 10.
Finally, a permerror is not just one broken line. DMARC passes only if SPF or DKIM aligns and passes — so when SPF collapses into permerror, any mail that DKIM does not cover can fail DMARC too and end up quarantined or bounced. After cleaning up SPF, review your policy and reporting (rua) with the DMARC record generator so you can catch regressions quickly.