RFC 7208 caps the number of DNS-querying terms a receiver must evaluate when checking an SPF record at ten. Go over it and the result is permerror — not a soft failure, not a partial pass. For DMARC purposes the SPF check simply did not succeed.
The limit exists to stop SPF being used to amplify DNS traffic. It bites because the cost is not visible in your own record.
What counts
These terms each consume one lookup:
include:aanda:mxandmx:ptr(deprecated; remove it)exists:redirect=
These are free: ip4:, ip6:, all, and the exp= modifier.
The trap is that the count is recursive. An include costs one lookup for itself, plus every lookup inside the record it points at. A record with four includes can easily cost twelve.
There are two secondary limits worth knowing: mx and ptr must each not return more than ten records, and no more than two of your lookups may return an empty result (a “void lookup”). Both also produce permerror.
Counting it properly
Take a record that looks entirely reasonable:
v=spf1 include:_spf.google.com include:sendgrid.net
include:servers.mcsv.net include:spf.protection.outlook.com ~allFour includes, so four lookups — except each of those expands. _spf.google.com contains further includes of its own. To get the real number you have to resolve the chain, which is what the health check does: it walks the includes and reports the total rather than the surface count.
You can do it by hand with dig +short TXT _spf.google.com and following each result, but it is tedious and the answer changes when a provider edits their own record — which they do, without telling you.
Getting under the limit
Remove senders that no longer send
Start here. Most overrun records contain includes for a platform the business stopped using two years ago. Free, and zero risk.
Replace an include with the IPs behind it
If a provider publishes a stable, small set of addresses, substituting ip4: entries for the include costs nothing against the budget. The catch is real: when the provider changes their IPs, your SPF silently stops authorising them. Only do this where the provider documents the addresses as fixed, and write down that you have done it.
Move senders to subdomains
The most durable fix. Send marketing from mail.yourdomain.com and application mail from notify.yourdomain.com, each with its own SPF record and its own ten-lookup budget. Under relaxed DMARC alignment — the default — a subdomain still aligns with the parent in the From header, so nothing breaks.
This also separates reputation between streams, which is worth doing regardless.
SPF flattening, carefully
Flattening resolves every include into a literal IP list, usually on a schedule. It works, and it shifts the problem: you now depend on something re-flattening correctly and forever. If the job fails quietly, your record goes stale and legitimate mail starts failing SPF. If you use a flattening service, monitor it like any other piece of production infrastructure.
Lean on DKIM instead
DMARC passes if either SPF or DKIM passes with alignment. A sender that signs with DKIM using your domain does not need to be in SPF at all for DMARC purposes. Removing SPF entries for DKIM-signing senders is often the cleanest reduction available, though it does leave those senders failing a bare SPF check at the few receivers that still weigh one.
After you change it
Verify from a public resolver, not the provider dashboard, and re-count. Then send a test message through each sending platform and confirm spf=pass in the received headers. An SPF record that parses is not the same as an SPF record that authorises the senders you actually use.