Fixing "SPF too many DNS lookups" (PermError)
By James Bayliss · Updated · Reviewed
In this guide
Why the limit exists
RFC 7208 §4.6.4 caps lookups so that checking one message can't be turned into a flood of DNS queries against third parties. The limit applies to the whole evaluation, not to each include. If Microsoft's include uses two lookups and your record has nine other terms that each use one, you're already at 11.
When the limit is exceeded, the result is permerror. Receivers treat that differently:
- Many treat permerror as an SPF failure.
- DMARC treats it as "SPF did not pass", so your mail now depends entirely on DKIM alignment.
- Some receivers log it and move on, which is why the problem can go unnoticed for weeks.
What counts, and what doesn't
| Term | Lookups counted |
|---|---|
include: | 1, plus everything inside the included record |
a, a:host | 1 |
mx, mx:domain | 1 (the MX query). Resolving up to 10 MX hosts is not counted towards the 10, but more than 10 MX hosts is itself a permerror |
exists: | 1 |
ptr | 1 |
redirect= | 1, plus the target record's terms |
ip4:, ip6:, all | 0 |
exp= | 0 (only fetched after a failure, and not counted) |
There is a second, lesser-known limit: no more than 2 void lookups. A void lookup is a query that returns NXDOMAIN or no records, for example an include: pointing at a vendor domain that has since removed its SPF record, or an a: for a decommissioned host. Three of those also produce a permerror.
Count your lookups
Run your domain through the Email Record Lookup: it walks every nested include and reports the total. To see the evaluation path for a specific sender, use the SPF validator with one of that sender's IPs. It lists every record it fetched, in order.
Here's a record that fails:
v=spf1 a mx include:spf.protection.outlook.com include:_spf.google.com
include:sendgrid.net include:mail.zendesk.com include:_spf.salesforce.com
include:spf.mandrillapp.com ip4:203.0.113.25 -all
Counting it: a (1) + mx (1) + six includes (6) = 8 at the top level. Several of those includes contain further includes, which pushes the real total past 10. The record looks reasonable; its true cost is hidden in the vendors' records, which can change without notice.
Five ways to get under the limit
1. Remove senders you no longer use
This is the cheapest fix. Old includes linger for years after a tool is retired. Confirm against DMARC aggregate reports: if a sender hasn't appeared in 30 days of reports, its include can probably go.
2. Replace a and mx with explicit addresses
a and mx are convenient but cost lookups. If your own mail server's address is stable, ip4:203.0.113.25 does the same job for zero lookups. On a domain whose mail is hosted entirely by Microsoft 365 or Google Workspace, mx usually adds nothing at all: the provider's include already covers its servers.
3. Check whether each vendor needs to be in SPF at all
SPF only matters for the envelope (Return-Path) domain. Many platforms send with their own bounce domain unless you configure a custom one. In that case, your include does nothing for DMARC, and the vendor needs aligned DKIM instead. Remove the include, set up DKIM signing with your domain, and confirm with a test message.
4. Move senders to subdomains
Give each high-volume platform its own subdomain, for example news.example.com for marketing mail and support.example.com for the help desk. Each subdomain has its own SPF record with its own 10-lookup budget. DMARC with relaxed alignment still passes, because the organisational domain matches. As a bonus, reputation problems on one stream stay isolated from your staff mail.
5. Flatten carefully, or not at all
"Flattening" replaces an include: with the IP ranges it currently resolves to. It removes lookups but creates a maintenance problem: when the vendor adds a range, mail from it fails SPF until you notice. Only flatten:
- your own infrastructure, which you control; or
- vendors that publish stable ranges, with an automated job (or a managed service) that re-checks and updates the record.
Never hand-flatten a large cloud provider's include. Microsoft and Google change their ranges.
Watch out for these traps
- Fixing the record but keeping a second one. Two
v=spf1records is a different permerror with the same symptom. - Using
include:to "split" one record into two of your own.include:_spf2.example.comstill counts its contents towards the same 10. - Assuming the vendor's include is small. Check it today and again next quarter. Includes grow.
- Relying on SPF alone. Even at 9 lookups, a forwarded message fails SPF. DKIM is what keeps DMARC passing through forwarding, so make sure every sender signs.
From the field: Too many lookups tends to be the one of the bigger issues typically encountered. A flattening service is your best bet to resolve this and not have to constantly validate that your vendor did not change their IP addresses.
After the fix
- Publish the new record and wait out the old record's TTL; the DNS Name Lookup shows the TTL.
- Re-check the count in the Email Record Lookup.
- Test one IP from each remaining sender in the SPF validator.
- Watch DMARC aggregate reports for a week for any sender that now fails.
Sources
Check it now
SPF Validation Is this IP address, or this whole range, allowed to send mail for the domain?
Related guides
- SPF explained: how to read, write and audit an SPF record
How SPF works, what each mechanism and qualifier means, how receivers evaluate a record, and the mistakes that make SPF fail for every message.
- DMARC alignment, explained: why SPF passes but DMARC fails
Which domains DMARC compares, relaxed vs strict alignment, and how to fix the most common "SPF pass, DMARC fail" and "DKIM pass, DMARC fail" cases.
- Why is my email going to spam? A diagnostic checklist for admins
A step-by-step checklist for why legitimate mail lands in junk: authentication, alignment, IP and domain reputation, reverse DNS, content and list hygiene.