SPF too many DNS lookups is one of the most common reasons an SPF check returns a permerror. The SPF standard allows only ten lookups per evaluation, and every include for a sending service quietly spends some of that budget. This guide shows what counts, how to count your own record, and the safe ways to bring it under the limit.
Check the exact limit rules. The limits come from RFC 7208, the SPF standard. A receiver that hits them returns permerror, and what it does next depends on the receiver, so fix the cause rather than hoping it is ignored.
What counts toward the limit
| Term | Costs a lookup? | Notes |
|---|---|---|
| include: | Yes, plus everything inside it | The most common source of overruns |
| a and a: | Yes | Often added without need |
| mx and mx: | Yes, and each MX host may need more lookups | Only keep if you send from your MX hosts |
| exists: | Yes | Used by some vendor setups |
| redirect= | Yes | Replaces the record, so nested lookups count |
| ptr | Yes | Discouraged: remove it |
| ip4: and ip6: | No | Free, but you must keep the ranges current |
| all | No | The final term |
Step 1: Confirm the problem
Send a message to a Gmail address and open Show original. An SPF result of permerror, or text such as too many DNS lookups, tells you that the record is the cause. An SPF checker that displays the lookup tree will show the count directly. See the authentication guide for the basics.
Step 2: Count your lookups
Take this example record. It looks short, but each include expands to more terms.
example.com. TXT "v=spf1 include:_spf.google.com include:mailer-one.example include:mailer-two.example include:crm.example mx a ~all"
| Term | Lookups used | Running total |
|---|---|---|
| include:_spf.google.com | 1 plus 3 nested | 4 |
| include:mailer-one.example | 1 plus 2 nested | 7 |
| include:mailer-two.example | 1 plus 1 nested | 9 |
| include:crm.example | 1 plus 2 nested | 12 |
| mx | 1 plus MX hosts | 13 or more |
| a | 1 | 14 or more |
The numbers for the vendors are illustrative. Real records change, which is why you count with a tool and recount regularly.
Step 3: Remove what you do not need
- Delete includes for services you no longer use, including old newsletter tools and trial accounts.
- Remove ptr entirely.
- Remove mx and a unless your own servers send mail for this domain.
- Fix includes that point to domains that no longer exist, because they count as void lookups.
- Check that you do not repeat the same include twice.
Step 4: Restructure what remains
| Method | How it works | Benefit | Risk |
|---|---|---|---|
| Subdomains per stream | Send each service from its own subdomain with its own SPF record | Each gets ten lookups and its own reputation | More DNS to manage and each domain needs authentication |
| Fixed ip4 ranges | Replace an include with the vendor ranges | No lookups | Breaks if the vendor changes ranges |
| Managed flattening | A service rewrites the record when ranges change | Keeps lookups low with updates | Depends on a third party staying current |
| Custom return-path | Use the provider return-path domain so SPF aligns on its own domain | Your root record needs fewer includes | Needs setup at the provider |
| Rely on DKIM and DMARC | Keep SPF small and let aligned DKIM carry authentication | Resilient to SPF changes | Not a replacement for a valid record |
Do not flatten once and forget. A flattened record that is not refreshed is a delayed outage. If you use ip4 ranges copied from a vendor, set a reminder to check them, or choose a service that updates them for you.
Step 5: Publish one record and retest
Merge everything into a single TXT record that starts with v=spf1. If a TXT value exceeds 255 characters, split it into several quoted strings inside the same record, as your DNS provider allows. After publishing, wait for the TTL and check again.
dig +short TXT example.com
# "v=spf1 include:_spf.google.com include:mailer-one.example ip4:203.0.113.0/24 ~all"
Common mistakes
| Mistake | Result | Fix |
|---|---|---|
| Two separate SPF TXT records | Permerror | Merge into one record |
| An include for a domain that does not exist | Void lookup, possible permerror | Remove or correct it |
| Adding a vendor include without recounting | Lookups pass ten | Recount after every change |
| Typing the record with curly quotes or extra spaces | Syntax error | Copy as plain text |
| Using ptr | Slow, unreliable and counted | Replace with ip4 or include |
| Putting SPF on the wrong host | No record found at the sending domain | Publish at the domain in the return-path |
After the record is healthy, check the next layer. A DMARC policy only passes if SPF or DKIM aligns, so read how to use DMARC reports to find any sender you missed.
SPF still failing? Send us your domain and the header of a failed message and we will help you read the result.
Further reading and sources
Frequently asked questions
What does SPF too many DNS lookups mean?
The SPF specification allows at most ten DNS lookups while a receiver evaluates a record. If your record and everything it includes needs more, the receiver stops and returns a permanent error, known as permerror. Most receivers then treat SPF as failed for that message.
Which SPF terms count toward the limit?
The include, a, mx, ptr and exists mechanisms and the redirect modifier each cause a DNS lookup and count toward the limit. The ip4, ip6 and all terms do not, because they need no lookup. Lookups inside an included record count as well.
Does a permerror always make my mail fail?
SPF itself fails, but your mail can still pass DMARC if DKIM passes and aligns with the From domain. That is one more reason to sign every message with DKIM. Do not rely on that as a fix, because some receivers weigh a broken SPF record negatively.
What is a void lookup?
A void lookup is a DNS query that returns no records or a non-existent domain. The specification allows at most two of them. An include that points to a domain that no longer exists counts as one, so stale includes can break a record even when the total is below ten.
How do I count the lookups in my record?
Look at each include, a, mx, exists and redirect term, then open every included record and do the same, adding nested lookups as you go. An SPF checker that shows the full tree does this for you. Re-check after any change at a vendor, because included records can grow without notice.
What is SPF flattening?
Flattening replaces include terms with the IP ranges they contain, written as ip4 and ip6 terms, so no lookups are needed. It solves the limit but has a risk: if a vendor changes its IP ranges and your flattened copy is not updated, legitimate mail starts to fail. Use a service that refreshes the record automatically, or flatten only ranges that rarely change.
Can I have two SPF records?
No. A domain must publish exactly one SPF record, which is a single TXT record that starts with v=spf1. Two records cause a permerror. Merge them into one.
Should I use all, tilde all or minus all?
The ending decides what receivers do with mail from unlisted sources. Tilde all (~all) is a soft fail and is common while you are still finding every sender. Minus all (-all) is a hard fail and is safer once the record is complete. Because DMARC is the policy that matters most, many senders keep ~all and rely on DMARC for enforcement.
Why not just use the ptr mechanism?
The ptr mechanism is slow, unreliable and discouraged by the specification itself, and it counts toward the limit. Replace it with ip4, ip6 or include terms.
How can subdomains help?
SPF is evaluated per domain, so each subdomain has its own limit of ten lookups. Sending marketing mail from a subdomain such as mail.example.com and transactional mail from another gives each stream its own record and its own budget, and also separates their reputations.