Your SPF record looks fine: a few includes for your mailbox provider, newsletter tool and CRM, ending in -all. Yet a message header says spf=permerror, your DMARC reports show SPF errors, or a checker reports “too many DNS lookups”. The cause is usually the limit of 10 DNS-querying terms in the SPF standard, which also counts the lookups hidden inside every include.
This guide explains which terms count and which do not, the separate limit on void lookups, how to count your total by hand, how to get back under ten without losing legitimate mail, why flattening needs care, and why a name may carry only one SPF record. All domain names and IP addresses are examples.
Scope of this guide
The free Launch Readiness Snapshot reads the SPF record on the exact hostname you enter and counts the DNS-querying terms in that record only. It does not follow include: or redirect=, count void lookups or send mail, and it is not a pentest.
What “too many DNS lookups” means
When a receiving server checks SPF, it reads the TXT record that starts with v=spf1 on the envelope-sender domain (the MAIL FROM address, later shown as Return-Path) and evaluates its terms from left to right. Some terms make the receiver query DNS again. RFC 7208, section 4.6.4 limits those terms to 10 per check, including the ones inside every record you include. When an evaluation needs an eleventh, the receiver must stop and return permerror, the result for published records that could not be correctly interpreted.
You usually notice it in one of three places: the Authentication-Results header of a delivered message (RFC 8601), for example spf=permerror smtp.mailfrom=example.com; a bounce message that mentions too many lookups; or SPF errors in your DMARC aggregate reports.
Two details make the error confusing. Receivers count lookups during evaluation, and evaluation stops at the first term that matches. Mail from a service listed early can still pass, while mail from a service whose include sits after the tenth lookup gets permerror, so the problem can look intermittent. And permerror is not a fail: SPF simply stops helping. DMARC passes when SPF or DKIM passes for a domain aligned with the From address (RFC 9989), so a message with an aligned DKIM signature still passes, and a message that relied on SPF alone does not. Beyond that, how a receiver treats permerror is its own decision.
Which SPF terms count toward the limit, and which do not
| Term | Counts toward the 10 | What else to know |
|---|---|---|
include: | 1, plus every lookup in the included record | If the included name has no SPF record, the result is permerror |
a, a: | 1 | Queries the name’s A or AAAA records, depending on whether the sender connected over IPv4 or IPv6 |
mx, mx: | 1 | The address lookups for the MX hosts it returns have their own, separate limit of 10 |
ptr | 1 | RFC 7208 says it SHOULD NOT be published |
exists: | 1 | Matches if the constructed name has an A record; often used with macros |
redirect= | 1, plus every lookup in the target record | Ignored when the record contains an all term |
ip4:, ip6: | 0 | The address is compared directly, without a query |
all | 0 | Sets the result for every sender not matched earlier |
exp= | 0 | Queried only after a fail, to fetch an explanation text |
Your own v=spf1 record | 0 | The first TXT query is not a term |
The budget belongs to the whole evaluation, not to a single record. An include costs one lookup for itself and then whatever the record behind it costs, down to the last nested level. Providers change their own records, for example by spreading their address ranges across more nested includes, so your total can change without any edit on your side.
The limit exists because SPF records make receivers send DNS queries on the publisher’s behalf; section 11.1 of RFC 7208 describes how an attacker could otherwise use that to flood a third party’s DNS. The RFC also suggests a time limit for the whole check, of at least 20 seconds. Running out of time gives temperror, a temporary error, rather than permerror.
The second limit: no more than two void lookups
RFC 7208 adds a separate limit for lookups that come back empty: an answer with no records (NOERROR with an answer count of zero) or a Name Error (NXDOMAIN, the name does not exist). These are called void lookups. Implementations SHOULD allow no more than two, and exceeding that also gives permerror, even when the total is still under 10. It keeps an SPF record from sending receivers after long lists of names that do not exist.
Void lookups usually come from leftovers:
a:old-web.example.comafter the old server’s DNS name was deleted.mxormx:example.orgon a name without MX records. The mechanism must not fall back to the name’s A record, so it simply finds nothing.aon the bare domain after the website moved to a host that only answers onwww.
An include: is stricter than that. If the included name does not exist or publishes no SPF record, the include does not just count as void: it makes the whole result permerror at once (section 5.2). That is what happens when a provider you stopped using retires the domain your record still includes. Query every name your record points to; a name that returns nothing should be fixed or removed.
How to count your SPF lookups by hand
Start from the envelope-sender domain, which you can read in the Return-Path header of a message you sent, and walk the record recursively:
- Read the record:
dig +short TXT example.com, ornslookup -type=TXT example.comon Windows. - Score 1 for each
include,a,mx,ptr,existsandredirect; score 0 forip4,ip6andall. - For every include and redirect, read the record it points to and score it the same way, as deep as the nesting goes.
- Add everything up, and write down any name that returned no records.
Here is a hypothetical record with only five DNS-querying terms on its face:
example.com. TXT "v=spf1 mx include:_spf.mail.example.net include:spf.crm.example.org include:news.example.net a -all"| Term | Lookups | Why |
|---|---|---|
mx | 1 | The MX query for example.com |
include:_spf.mail.example.net | 4 | 1 for the include, 3 for three nested includes in that record |
include:spf.crm.example.org | 2 | 1 for the include, 1 for an a: term inside it |
include:news.example.net | 3 | 1 for the include, 1 for a nested include, 1 for an exists: term in that one |
a | 1 | A leftover entry for an old web server |
-all | 0 | No query |
| Total | 11 | One over the limit |
The total is the worst case. A sender matched by the first include needs at most five lookups and passes. A sender that matches nothing earlier reaches the final a, the eleventh lookup, so forged mail gets permerror instead of the fail that -all was meant to produce. Count again whenever you add a sending service, and from time to time anyway, because included records change without notice.
How to get back under ten without losing mail
- Remove includes you no longer use. A previous mailbox provider, a newsletter tool you cancelled, a CRM trial. DMARC aggregate reports show which sources actually send as your domain, which helps you spot includes nobody needs. Check with whoever owns each service before you remove it.
- Check whether an include is evaluated at all. SPF is checked against the envelope-sender domain. If a service’s messages show its own domain in
Return-Path, receivers check that domain’s SPF record, not yours, and your include does nothing for that mail. Confirm in the provider’s documentation before you take it out. - Replace
aandmxwithip4andip6for servers you control. If your own server sends from 192.0.2.10,ip4:192.0.2.10costs nothing, whileacosts a lookup. Ask whethermxbelongs there at all: the servers that receive your mail do not necessarily send it, and if they belong to your mailbox provider, its include may already list its sending servers. Update the address when the server moves. - Give each high-volume sender its own subdomain. Let a newsletter or ticketing service use a bounce domain such as
news.example.comas its envelope sender, with its own SPF record and its own limit of 10. SPF is not inherited, so the subdomain needs that record. Under DMARC’s default relaxed alignment,news.example.comstill aligns with a From address at example.com. Many services call this a custom return-path or bounce domain. - Drop
ptr. RFC 7208 says it SHOULD NOT be published: it is slow, it depends on reverse DNS controlled by whoever owns the connecting IP address, and it uses up lookups. Replace it withip4/ip6or the provider’s include. - Do not treat reordering as a fix. Moving the busiest sender to the front means fewer messages reach the eleventh lookup, but the record stays broken for everything further down, including forged mail that should hit
-all.
DKIM eases the pressure as well. DMARC needs only one aligned pass, and DKIM generally survives forwarding while SPF does not. Make sure every service signs with your domain, then trim the SPF record.
SPF flattening: fewer lookups, more upkeep
Flattening replaces an include with the ip4 and ip6 ranges it resolves to today. The lookup count drops, but your record now holds a copy of someone else’s list, and the copy does not update itself.
| Risk | What happens | How to limit it |
|---|---|---|
| The provider adds or changes ranges | Mail from the new addresses fails SPF, and nothing alerts you | Flatten only providers that publish stable, documented ranges, and recheck them on a schedule |
| The provider stops using ranges | Addresses it gave up, which may later serve someone else, stay authorized in your record | Remove ranges the provider no longer lists |
| The record grows | RFC 7208 recommends keeping SPF answers within 512 octets; answers too large for one UDP packet can be silently ignored where firewalls interfere with DNS over TCP or EDNS0 | Flatten only the few includes that cost the most |
| The infrastructure changes often | Large cloud platforms rotate their sending addresses | Keep their include; Microsoft, for example, advises against flattening its Microsoft 365 include |
Automated flattening services resolve the includes on a schedule and rewrite your record. That deals with stale ranges, but it gives a third party a role in your DNS, and a failed update breaks your SPF. Try the other fixes first. If you do flatten, note which include you replaced and when, compare against the provider’s published ranges regularly, and test SPF after each change (Microsoft Learn gives the same advice for its own customers).
One SPF record per name, split the right way
A name must have exactly one TXT record that starts with v=spf1. With two, the receiver cannot choose and returns permerror (RFC 7208, section 4.5). This often happens when a new service’s setup guide says to “add this TXT record” and someone adds a second SPF record instead of editing the first. A second record therefore does not double the budget; merge the two:
# Wrong: two SPF records on one name
example.com. TXT "v=spf1 include:_spf.mail.example.net -all"
example.com. TXT "v=spf1 include:spf.crm.example.org ~all"
# Right: one record
example.com. TXT "v=spf1 include:_spf.mail.example.net include:spf.crm.example.org -all"Other TXT records on the same name, such as site verification tokens, are fine; only records that start with v=spf1 count. A single string inside a TXT record holds at most 255 characters. A longer SPF record stays one TXT record made of several quoted strings, which receivers join without adding spaces (section 3.3), so end a string with a space where a term ends:
example.com. TXT "v=spf1 ip4:192.0.2.0/24 ip6:2001:db8::/32 include:_spf.mail.example.net " "include:spf.crm.example.org -all"Several other mistakes produce the same permerror: a syntax error anywhere in the record, such as include= instead of include: (section 4.6), or an include of a domain without an SPF record. SPF records are not inherited either, so every name used as an envelope sender needs its own record, and each one has its own limit of 10.
What the free SPF and DMARC checker counts
The free Launch Readiness Snapshot runs eight passive checks on one public domain, without signup; one of them reads mail DNS records. It is not a pentest and not the six-area audit, and it sends no mail.
- Exact hostname. It reads the SPF record on the name you enter, with no fallback to the parent domain. Enter the envelope-sender domain itself, for example example.com rather than www.example.com.
- Top-level count. It counts the DNS-querying terms in that record (
include,a,mx,ptr,existsandredirect) and flags more than ten as a medium risk signal. - Not followed. It does not follow
include:orredirect=, does not count void lookups and does not flag a second SPF record on the same name. The five-term example above passes this count even though receivers need eleven lookups, so do the recursive count yourself as well. - Other SPF signals.
+allis flagged as high risk and?allas low; a missing SPF or DMARC record is flagged when the host has MX records.
To open the mail DNS check first, use the free SPF and DMARC checker: it runs the same snapshot and shows that check above the other seven. For the rest of the record, from ~all versus -all to moving DMARC from none to reject, see the SPF and DMARC guide.
Common questions
What does “SPF permerror: too many DNS lookups” mean?
Evaluating your SPF record needed more than 10 DNS-querying terms, counting the ones inside included records. RFC 7208 requires receivers to stop and return permerror at that point, so SPF can no longer help the message pass DMARC.
Do ip4 and ip6 count toward the SPF lookup limit?
No. ip4, ip6 and all need no DNS query and are not counted. include, a, mx, ptr, exists and redirect count as one each, and an include or redirect also adds every lookup in the record it points to.
Is the SPF limit 10 includes or 10 lookups?
10 lookups. A record with four includes can exceed the limit when the included records contain includes, a or mx terms of their own. Count recursively through every include and redirect, not just the terms you can see.
Can I publish a second SPF record to get more lookups?
No. Two TXT records starting with v=spf1 on the same name make the result permerror. Merge them into one record, or move a sender to its own subdomain, which has its own record and its own limit of 10.
Does SPF flattening fix the 10-lookup limit?
It lowers the count, but the copied IP ranges go stale when the provider changes them, and legitimate mail from new addresses then fails SPF. Remove unused includes and use subdomains first; flatten only providers with stable, documented ranges, and recheck them regularly.
Will DMARC fail if my SPF record returns permerror?
Not necessarily. DMARC needs only one aligned pass, so mail with a valid DKIM signature aligned with the From domain still passes. Mail that relied on SPF alone does not, which is why fixing the record matters.
Sources & further reading
- RFC 7208: Sender Policy Framework (SPF)www.rfc-editor.org
- RFC 7208, section 4.6.4: DNS lookup limitswww.rfc-editor.org
- RFC 9989: DMARCwww.rfc-editor.org
- RFC 8601: Message header field for indicating message authentication statuswww.rfc-editor.org
- Microsoft Learn: Set up SPF to identify valid email sources for your Microsoft 365 domainlearn.microsoft.com
Prepared by the Sitelemetry editorial team. Explore the linked sources for further detail.



