SYSTEMS OPERATIONAL
Domains

SPF Permerror: Fix 'Too Many DNS Lookups' Once and for All

Getwebup 6 min read

Your newsletter tool says the send worked. Half your list never got it, and the ones that did found it in spam with a big red "this sender could not be verified." A quick check at mail-tester.com shows it: permerror on your SPF record. Not "missing SPF" - your SPF record exists, and that's exactly the problem. It's gotten too big.

Symptom: SPF Shows "Permerror" or "Too Many DNS Lookups"

You'll usually spot this one of a few ways:

  • A bounce-back or spam-report header showing spf=permerror instead of pass or fail
  • Tools like MXToolbox or mail-tester.com flagging "SPF Permanent Error: Too many DNS lookups"
  • Mail that used to deliver fine suddenly starts landing in spam after you connect a new sending tool (a CRM, a helpdesk, a marketing platform)
  • Google Postmaster Tools or your DMARC aggregate reports showing SPF failing intermittently, not consistently - a classic sign you're right at the edge of the limit

The frustrating part: the record isn't broken syntactically. Every include and every IP range in it is valid on its own. It just adds up to more DNS lookups than the spec allows, and receiving mail servers are required to treat that as a hard failure - not a warning.

Cause: SPF's 10-Lookup Ceiling

RFC 7208 caps SPF evaluation at 10 DNS lookups per check. Once a receiving server crosses that limit while resolving your record, it stops and returns permerror - and most receivers then treat that the same as a straight-up SPF fail. This isn't a Gmail quirk or a Getwebup limit; it's baked into how the protocol was designed to stop SPF checks from becoming their own DoS vector.

The mechanisms that count toward the 10:

MechanismCounts as a lookup?Notes
include:YesPlus every lookup inside the included record, recursively
aYesOne lookup per domain referenced
mxYesOne lookup for the MX record, plus one per MX host it resolves to
ptrYesDeprecated - avoid entirely, it's slow and unreliable
exists:YesOften used in shared-hosting SPF setups
redirect=YesReplaces the whole evaluation with another domain's record
ip4: / ip6:NoFree - raw IP ranges never cost a lookup
allNoTerminal qualifier, no lookup needed

The trap is that include: is recursive. Your record might have three includes, but if each of those points to a provider that itself includes two more domains, you're not at 3 - you could easily be at 9 or 10 before you've added your own mail server. Add one more marketing tool and you're over.

Step 1: Actually Count Your Lookups

Don't guess - count. Pull your current record first:

dig TXT yourdomain.com +short

You'll get something like:

"v=spf1 include:_spf.google.com include:sendgrid.net include:mailchimp.com include:secureserver.net ~all"

Now walk each include manually - dig TXT _spf.google.com +short, then dig TXT on whatever that resolves to, and so on - or save yourself the manual recursion and run the record through a free SPF lookup counter (MXToolbox's SPF check tool shows the full expanded tree and the exact count). Either way, get the real number before you touch anything. It's common to find you're already at 11 or 12 without realizing it.

Step 2: Find What's Actually Bloating the Record

Once you see the expanded tree, the usual culprits are:

  • Dead includes. An ESP you stopped using two years ago, still sitting in the record, still costing lookups on every single check.
  • Duplicate coverage. Your hosting provider's include and your registrar's default include both authorizing the same sending IPs.
  • Chained third-party includes. Some transactional-email or marketing tools route their own SPF through two or three layers of their own infrastructure providers, each one a lookup you don't control.
  • Using a or mx when a direct ip4: would do. If your mail server's IP never changes, ip4:203.0.113.10 does the same job as mx for zero lookup cost.

Cut anything you don't recognize or no longer use before you optimize what's left - it's the fastest way to claw back headroom.

Step 3: Flatten the Record

"Flattening" means replacing a lookup-costing mechanism with the raw IP ranges it resolves to, so the receiving server doesn't have to chase it down. Take an include that only resolves to a couple of fixed IP blocks and inline those directly:

Before:
v=spf1 include:mail.oldvendor.com ~all

After:
v=spf1 ip4:198.51.100.0/24 ip4:198.51.100.128/25 ~all

This drops that entry from 1+ lookups to zero. The catch: you now own keeping those IPs current. If the vendor rotates their sending infrastructure and you don't update the flattened ranges, your mail starts failing SPF for the opposite reason - unauthorized sender. Flatten vendors with stable, published IP ranges (most transactional email providers publish these). For anything that changes its sending IPs frequently, keep it as an include: and instead cut the fat elsewhere in the record.

If you're managing a record with genuinely many senders and don't want to hand-maintain IP lists, an SPF-flattening service (there are several free and paid ones) will auto-refresh a flattened record for you on a schedule. Worth it once you're juggling five or more senders; overkill for two or three.

Step 4: Publish and Verify

Update the TXT record at the root of your domain - in cPanel that's Zone Editor → Manage on the @ host. Remember only one SPF record is allowed per domain; if you see two v=spf1 TXT entries, merge them into one or the record fails outright regardless of lookup count.

After publishing, don't just assume it worked:

  1. Re-run the SPF lookup counter and confirm you're now under 10, ideally with a few lookups of headroom for the next tool someone adds
  2. Send a test message to mail-tester.com and confirm SPF shows pass, not permerror or softfail
  3. Check DMARC aggregate reports over the next few days if you have DMARC set up - they'll show real-world pass/fail rates across every sender, not just your test

DNS changes for a TXT record are usually visible within 30-60 minutes, but give it a few hours before concluding a fix didn't take.

Prevention: Keep Headroom in the Record

PracticeWhy it matters
Audit the SPF record whenever you add or drop a sending toolBloat happens one "just add this include" at a time, never all at once
Prefer ip4:/ip6: over a/mx for your own mail serverFree lookups, and your server IP rarely changes anyway
Never use ptrIt's deprecated, slow, and burns a lookup for something SPF no longer needs
Keep a running list of what each include is forMakes it obvious which ones are safe to remove later
Aim to stay at 6-7 lookups, not exactly 10Leaves room for the next marketing or helpdesk tool without another emergency fix

SPF's 10-lookup limit isn't going away, and it's not negotiable - it's enforced by every major receiver, not configurable on your end. The fix isn't clever DNS tricks, it's just keeping the record honest: only what's currently sending mail on your behalf, nothing left over from tools you stopped using two migrations ago.

Frequently asked questions

How do I know how many DNS lookups my SPF record is actually using?

Run your domain through an SPF lookup checker (MXToolbox's SPF record check is a common free one) - it expands every include recursively and shows the exact count. Manually running dig TXT on each include and its nested includes works too, but it's easy to undercount by hand since includes can be several layers deep.

Can I just add more IP addresses instead of using include: to avoid the lookup limit?

Yes - ip4: and ip6: mechanisms never count against the 10-lookup limit, only include, a, mx, ptr, exists, and redirect do. Flattening a stable include into its raw IP ranges is exactly how you claw back lookups, but you're then responsible for updating those ranges if the sender's infrastructure changes.

Will fixing SPF alone stop my mail from going to spam?

It removes one specific failure, but SPF is only one of three checks. If DKIM isn't signing your outgoing mail or DMARC isn't published, receivers can still flag messages as suspicious. Check all three together, not just the one that's currently throwing an error.

I fixed the record but mail-tester.com still shows the old error - why?

DNS TXT record changes typically propagate within 30-60 minutes, but caching resolvers and some receivers hold onto old records longer. Wait a couple of hours, then re-run dig TXT yourdomain.com directly against a public resolver like 8.8.8.8 to confirm the new record is actually live before re-testing.

Does void lookups count separately from the 10-lookup limit?

Yes - RFC 7208 also caps 'void lookups' (a lookup that returns no data or NXDOMAIN) at 2. Stale includes pointing at domains that no longer exist can trip this limit even if your total lookup count is otherwise under 10, so remove dead includes rather than leaving them in place.

#spf #dns #email-deliverability #permerror #dns-lookups #dmarc

Keep reading

Chat with Support