Your SPF record needs more than 10 DNS lookups to evaluate, so receivers return permerror instead of pass or fail. RFC 7208 §4.6.4 sets the limit at 10 terms that cause DNS queries, and include: counts everything inside the included record, not only the include itself. To fix it, remove senders you no longer use, replace a and mx with fixed ip4:/ip6: ranges where the addresses are stable, move marketing senders to a subdomain with their own SPF record, or flatten includes with a process that re-publishes automatically.
What the limit counts
RFC 7208 §4.6.4 says implementations “MUST limit the total number of those terms to 10 during SPF evaluation”. The counted terms are the include, a, mx, ptr and exists mechanisms and the redirect modifier. If the limit is exceeded the implementation “MUST return permerror”.
| Term | Costs a lookup? | Note |
|---|---|---|
include: | Yes, 1 plus whatever the included record uses | Nested includes add up |
redirect= | Yes, 1 plus the target’s terms | Replaces the whole record |
a, a:domain | Yes, 1 | |
mx, mx:domain | Yes, 1 | Each MX name’s address lookup is limited separately to 10 (§4.6.4) |
exists: | Yes, 1 | |
ptr | Yes, 1 | Discouraged by RFC 7208 §5.5 |
ip4:, ip6: | No | Compared directly with the connecting IP |
all | No |
Two further limits sit beside the main one. A separate cap applies to “void lookups”, queries that return no records or NXDOMAIN: the RFC says implementations SHOULD limit them to two, and exceeding that also gives permerror. A single mx mechanism must not trigger more than 10 address lookups.
Why a normal-looking record goes over
A record such as this looks short:
example.com. TXT "v=spf1 include:_spf.mailbox.example include:_spf.crm.example include:_spf.news.example include:_spf.helpdesk.example mx a ~all"
Each provider’s include record usually contains its own include: entries. If each of the four includes expands to two further includes, the evaluation already costs 4 + 8 + mx + a = 14 lookups. The record you see in DNS is not the number that matters; the expanded tree is.
An SPF checker has to follow every branch to count correctly. Run your domain through the SPF checker and read the include tree rather than the length of the TXT string. The MX lookup shows which hosts the mx term resolves to, which is useful when deciding whether to replace it with explicit addresses.
How to get back under 10
- Remove dead includes. Old newsletter tools, abandoned CRMs and former helpdesks are the most common cause. Search your sending logs or DMARC aggregate reports for the last 90 days before deleting anything.
- Replace
aandmxwith addresses. If your web server or mail server has a fixed IP,ip4:203.0.113.25costs nothing. The trade-off: when the IP changes you must edit SPF yourself, and a forgotten edit turns intofailorsoftfailfor your own mail. - Move bulk senders to a subdomain. Send campaigns from
news.example.comwith a separate SPF record there. Each domain gets its own budget of 10. This only helps if the subdomain is actually used in the envelope sender or From address; see DMARC fails although SPF and DKIM pass for how that interacts with alignment. - Flatten with care. Flattening replaces includes with the IP ranges they resolve to. It fits under the limit, but providers change their ranges without notice. A flattened record that is not regenerated automatically will start failing for legitimate mail with no visible error on your side. Use it only with a service or script that re-checks the source records and republishes on a schedule, and keep the original includes documented.
Do not try to solve the problem by publishing two SPF records on one name. RFC 7208 §4.5 requires exactly one record starting with v=spf1; two make the result permerror as well.
What changes at the receiver
Permerror is not the same as fail. RFC 7208 §2.6.7 defines it as “the domain’s published records could not be correctly interpreted”. Receivers handle it differently: some treat it like no SPF, some treat it as a failure. If your DMARC policy depends on SPF alone, a permerror can push mail into spam or cause rejection under p=reject. DKIM that aligns with the From domain is the safety net; with it, DMARC still passes while you repair SPF.
FAQ
Is the limit 10 includes or 10 lookups?
Ten lookups across all counted terms, including those reached through includes. ip4, ip6 and all are free.
Does redirect= count too?
Yes. RFC 7208 §4.6.4 lists the redirect modifier among the counted terms.
My checker says 9 but a receiver reports permerror. Why? Void lookups (more than two includes or names that return nothing) also cause permerror, and some checkers do not count them. A record that changes between two checks, for example through a provider updating its own include, can also cross the line later.
Sources
- RFC 7208, §4.6.4 DNS lookup limits: https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4
- RFC 7208, §2.6 Results of evaluation: https://www.rfc-editor.org/rfc/rfc7208#section-2.6
- RFC 7208, §4.5 Selecting records: https://www.rfc-editor.org/rfc/rfc7208#section-4.5
- RFC 7208, §5.5 ptr: https://www.rfc-editor.org/rfc/rfc7208#section-5.5