Deliverability
SPF "Too Many DNS Lookups" (PermError): How to Fix It
The SPF “too many DNS lookups” error means evaluating your SPF record required more than 10 DNS queries, so receivers stop and return permerror. The limit comes from RFC 7208 section 4.6.4, and it counts every include, a, mx, exists, ptr, and redirect, including the ones nested inside your vendors’ records. To fix it, remove includes you no longer use, move some senders to their own subdomains, and replace a/mx with IP ranges where it’s safe.
Below is how to count your lookups accurately, which fixes are safe, and which create new problems.
What the SPF 10-lookup limit actually says
RFC 7208 puts several caps on SPF evaluation to protect DNS infrastructure from abuse:
| Limit | Value | Result if exceeded |
|---|---|---|
Terms that trigger DNS lookups (include, a, mx, ptr, exists, redirect) | 10 | permerror |
Address lookups per mx mechanism | 10 | permerror |
Address lookups per ptr record | 10 | extra records ignored |
| “Void” lookups (empty answer or NXDOMAIN) | 2 (a SHOULD) | permerror |
Things that don’t count: ip4, ip6, all, and the exp modifier. Microsoft’s SPF troubleshooting guide lists the same split.
Two subtleties catch people:
- Nesting counts. Microsoft’s example: an
includethat points to a record containing three more includes costs four lookups in total, not one. - Evaluation stops at the first match. Receivers read the record left to right and stop when the sending IP matches. Microsoft notes that a record with more than 10 potential lookups may still pass for some messages if the match comes early. That’s why the error looks intermittent: mail from your first-listed sender passes while mail from your last-listed one fails.
What the error looks like
You’ll see it in a few places:
- Authentication-Results headers on delivered mail:
spf=permerror (google.com: permanent error in processing during lookup of bounce@example.com: ...). - DMARC aggregate reports, where SPF results show
permerrorfor a source. Our guide on reading DMARC aggregate reports shows where to look. - Bounces. Microsoft says receivers may reject with errors like “The message exceeded the hop count” or “The message required too many lookups.” RFC 7208 section 8.7 suggests a
550 5.5.2reply when a receiver rejects for apermerror. - SPF checker tools that report a lookup count over 10.
Under DMARC, a permerror is treated as an SPF failure. If DKIM is aligned, DMARC still passes. If not, your DMARC policy applies.
How to count your SPF lookups
Do this once by hand so you understand your record. Start with your domain:
dig +short TXT example.com | grep spf1
"v=spf1 include:_spf.google.com include:mail.vendor-a.example.net include:spf.vendor-b.example.net mx a ~all"
Write down each term and its cost:
| Term | Direct cost | Then resolve its record and count again |
|---|---|---|
include:_spf.google.com | 1 | query it, count its includes |
include:mail.vendor-a.example.net | 1 | query it |
include:spf.vendor-b.example.net | 1 | query it |
mx | 1 | plus up to 10 address lookups (separate limit) |
a | 1 | |
~all | 0 |
Then fetch each included record and repeat:
dig +short TXT _spf.google.com
dig +short TXT mail.vendor-a.example.net
Keep going until you hit records with only ip4/ip6 terms. Add everything up. On Windows, Resolve-DnsName -Type TXT <name> does the same job.
Vendors change their records without warning, so a record that counted 9 last quarter may count 11 today. Re-check after adding any service, or use the SPF checker on this site, which does the recursive count for you.
How to fix SPF too many DNS lookups
Work through these in order. The early ones are free and safe; the later ones have trade-offs.
1. Remove includes for services you no longer use
Every old marketing tool, trial signup, and migrated help desk tends to leave its include behind. Check each include against your current vendor list. Dead includes are doubly harmful: if the vendor removed their record, the lookup returns nothing and counts as a void lookup too, and RFC 7208 allows only two of those.
2. Remove includes for services that don’t use your bounce domain
SPF is checked against the envelope sender (Return-Path), not the visible From. Many platforms send with their own bounce domain by default, such as bounces.vendor.example.net. In that case, receivers check the vendor’s SPF record, never yours, and your include for that vendor does nothing.
Look at the Return-Path header on a message each vendor sent. If it’s not under your domain, the include in your root SPF record is dead weight. (For DMARC, that vendor needs aligned DKIM instead, or a custom bounce domain under yours.)
3. Drop mx, a, and ptr where you can
ptris deprecated by RFC 7208 section 5.5 and should never be published. Remove it.mxauthorizes your inbound mail servers to send. Unless those same servers send outbound mail, you don’t need it. Mail hosted at Google or Microsoft sends from different IPs than the MX hosts, and is already covered by the include.aauthorizes your web server’s IP. Only keep it if the web server really sends mail as your domain; if it does, replace it with that server’sip4:address.
4. Move senders to subdomains
This is the most durable fix. Each hostname gets its own SPF record and its own budget of 10 lookups. Microsoft recommends it for exactly this reason and for reputation isolation:
example.com. TXT "v=spf1 include:_spf.google.com ~all"
news.example.com. TXT "v=spf1 include:mail.vendor-a.example.net ~all"
billing.example.com. TXT "v=spf1 include:spf.vendor-b.example.net ~all"
With relaxed DMARC alignment (the default), mail with a bounce domain of news.example.com still aligns with a From address of @example.com. See DMARC alignment: strict vs relaxed. The existing post on sending from subdomains instead of your root domain covers the reputation side.
5. Use custom bounce domains your vendors manage
Many platforms (Amazon SES calls it a custom MAIL FROM domain) let you point a subdomain like bounce.example.com at them. The SPF record for that subdomain contains only that vendor’s include, so it never touches your root record’s budget.
6. Replace an include with IP ranges (carefully)
If a vendor publishes a small, stable, documented IP list, you can swap their include for ip4: entries. Microsoft’s guidance says this is reasonable for vendors with stable ranges, but explicitly not for Microsoft 365 itself, whose sending IPs change frequently. If you do it, document what you replaced and review it at least quarterly, as Microsoft recommends.
Automated “SPF flattening” services do this continuously. They solve the count but create a new dependency: if the flattener lags behind a vendor’s IP change, your legitimate mail fails SPF. Our existing post explains why SPF flattening creates a worse problem than it solves for most senders. Use it as a last resort.
7. Lean on DKIM
You don’t need every sender in SPF to pass DMARC. If a service signs with aligned DKIM using your domain, DMARC passes even when SPF doesn’t apply. That’s often the cleanest way to drop a vendor from SPF entirely. See DKIM explained.
A worked example
Before (12 lookups by recursive count, permerror for senders matched late):
v=spf1 a mx include:_spf.google.com include:spf.crm.example.net
include:mail.oldtool.example.net include:spf.helpdesk.example.net
include:servers.newsletter.example.net ~all
Changes:
aandmx: web server doesn’t send; inbound MX is Google. Removed (saves 2).oldtool: cancelled last year; its record now returns NXDOMAIN. Removed (saves 1 lookup and 1 void lookup).newsletter: moved tonews.example.comwith its own record (saves at least 1, plus its nested includes).helpdesk: uses its own Return-Path domain and signs with aligned DKIM. Removed.
After:
example.com. TXT "v=spf1 include:_spf.google.com include:spf.crm.example.net ~all"
news.example.com. TXT "v=spf1 include:servers.newsletter.example.net ~all"
Both records now sit comfortably under the limit, with room for future tools.
How to keep it from happening again
- Own the record. One person or team approves every SPF change.
- Ask before adding. When a new tool says “add our include,” ask whether it can use a subdomain or a custom bounce domain instead.
- Monitor DMARC reports. A new
permerrorusually shows up there before customers notice. - Re-count quarterly. Vendors change their own records.
Authentication problems and list problems often show up together, especially after a platform migration. While you’re cleaning up DNS, run your contact list through our free email verifier to catch addresses on domains with no MX records, disposable domains, and typos, so the bounce rate doesn’t muddy your diagnosis. It works from syntax and DNS checks and doesn’t connect to mailboxes.
FAQ
Does the 10-lookup limit include nested includes?
Yes. Every DNS-querying term counts wherever it appears in the evaluation chain. An include that contains three more includes costs four lookups.
Does ip4 count toward the SPF lookup limit?
No. ip4, ip6, and all don’t trigger DNS queries, so they don’t count. That’s why replacing includes with IP ranges reduces the count, at the cost of maintenance.
Why do only some of my emails fail with SPF permerror?
Receivers stop evaluating at the first matching mechanism. Mail from senders listed early in the record matches before the 10th lookup and passes; mail from senders listed later triggers the limit and gets permerror.
Can I just create a second SPF record for the extra includes?
No. Two SPF records on the same hostname is itself a permerror under RFC 7208. Use subdomains, each with one record, instead.
Is SPF permerror the same as SPF fail?
No, but DMARC treats both as a failure to pass SPF. fail means the IP isn’t authorized; permerror means the record couldn’t be evaluated at all. If DKIM is aligned and passing, DMARC still passes.
Free email verifier: syntax, MX, disposable and role-based addresses, typos. Paste up to 100 at once.