Fix SPF “too many DNS lookups” (the 10-lookup limit)

SPF allows at most 10 DNS lookups; go over and SPF fails with a PermError. How lookups are counted, how to find costly includes, and safe ways to get under 10.

Updated September 30, 2026

SPF (RFC 7208) lets a receiver make at most 10 DNS lookups while checking your record. The mechanisms include, a, mx, ptr, exists and the redirect modifier each count, and so does every one of those inside the records you include. Go past 10 and SPF returns permerror, which DMARC treats as a fail. Fix it by removing senders you don’t use, moving senders that don’t need your SPF record out of it, and putting bulk mail on subdomains.

What the error looks like

The same problem shows up under different names depending on where you look:

  • In checkers: “SPF PermError: too many DNS lookups”, “SPF record exceeds 10 lookups” or “too many included lookups”.
  • In message headers: spf=permerror in Authentication-Results, or Received-SPF: permerror.
  • In DMARC aggregate reports: an SPF result of permerror for your own servers.

It often appears “suddenly” after you add one more service, or when a provider you include adds a nested include to its own record without telling you. Receivers typically count as they evaluate, so senders listed early may still pass while those after the limit fail, which makes the problem look intermittent.

What counts toward the 10-lookup limit

TermCounts?Notes
include:Yes, 1Plus every counted term inside the included record, recursively.
aYes, 1Also a:host.example.com.
mxYes, 1The address lookups for each MX host have their own separate cap of 10 per mx mechanism.
exists:Yes, 1Used for macro-based dynamic SPF.
ptrYes, 1Deprecated. Remove it.
redirect=Yes, 1Plus the terms in the target record.
ip4:, ip6:NoNo DNS query needed, so these are free.
allNoMatches everything.
exp=NoOnly fetched after a fail, to build an explanation.
Your own TXT recordNoThe first query that fetches your SPF record isn’t counted.

The 2 void-lookup limit

RFC 7208 also says receivers should allow no more than 2 “void” lookups: queries that return no records or a nonexistent domain. A third also produces permerror. The usual cause is an include: for a service you cancelled whose SPF record has since been deleted, or a typo in an include domain. These don’t just waste a lookup; they point at a name someone else might be able to register.

Worked example: counting lookups

Here’s a record for a company with a CRM, a help desk, a newsletter tool and an old payroll service (all names are placeholders):

Before: 12 lookups
v=spf1 a mx include:_spf.crm.example include:spf.helpdesk.example include:mail.newsletter.example include:_spf.payroll.example ~all
TermWhat it containsLookups
aYour web server’s A record1
mxYour inbound mail hosts1
include:_spf.crm.exampleThree more includes for the CRM’s IP ranges1 + 3 = 4
include:spf.helpdesk.exampleOne include for the help desk’s relay1 + 1 = 2
include:mail.newsletter.exampleOnly ip4 ranges1
include:_spf.payroll.exampleAn include, which itself ends with a redirect1 + 1 + 1 = 3
Total12 (over the limit)

Working through the fixes below:

  1. The web server doesn’t send mail, and the MX hosts only receive it: remove a and mx (−2).
  2. Payroll moved to a new vendor last year: remove the old include (−3).
  3. The newsletter tool supports a custom return-path, so newsletters go out with news.example.com as the envelope sender and that subdomain gets its own SPF record (−1).
After: 6 lookups
v=spf1 include:_spf.crm.example include:spf.helpdesk.example ~all

Aim for headroom, not exactly 10: at 6 or 7 you can add a sender, or absorb a provider growing its own record, without an emergency.

How to audit your SPF record

Counting by hand means fetching every included record, and every record those include. The SPF checker does it for you: it expands the whole tree, shows the lookup count for each include and flags void lookups. Then list what each include is for, and check your DMARC aggregate reports for the IPs actually sending as your domain.

Count your SPF lookups

See your SPF record, its total DNS-lookup count and any void lookups, plus DMARC and DKIM results.

How to fix “too many DNS lookups”, in order

1. Remove senders you don’t use

Old includes are the cheapest fix. Every service you stopped using, trial you never finished, and duplicate include (for example the same provider listed under two names) can go. If you aren’t sure, your DMARC reports tell you whether any mail still comes from that service’s IPs.

2. Take out senders that don’t need your SPF record

SPF only checks the envelope sender domain. Many email platforms send with their own return-path domain, so your SPF record is never consulted for their mail, and their include does nothing but cost lookups. For DMARC these senders pass on DKIM (or on a custom return-path subdomain with its own SPF). Confirm in a delivered message’s Return-Path header, or in your DMARC reports, before removing an include.

3. Put bulk senders on subdomains

Give marketing or transactional platforms their own subdomain, such as news.example.com or mail.example.com, as the envelope sender or the From domain. Each subdomain has its own SPF record with its own 10 lookups, and relaxed DMARC alignment still works. This also keeps a newsletter’s reputation separate from your staff mail.

4. Replace a and mx with ip4 or ip6 where the addresses are stable

If your own servers send mail from fixed IPs, list them as ip4: or ip6:, which cost nothing. Do this only for addresses you control and that rarely change.

5. SPF flattening, with care

Flattening replaces includes with the IP ranges they currently resolve to. It gets you to near-zero lookups, but a provider can change its ranges at any time, and a static flattened record silently stops matching when it does. If you flatten, re-check the source records automatically and often, and don’t flatten providers that say not to. Flattened records also grow long quickly.

6. Hosted or dynamic SPF

Hosted SPF services publish your record for you and manage the includes, often with an include: or redirect= from your domain. Some use SPF macros with exists: so the receiver asks about the exact sending IP in one lookup. With DMARC Dojo’s hosted SPF, your domain’s record is a redirect= to one we manage, and any sender change that would take it over 10 lookups is refused before it’s published.

More on SPF syntax is in what SPF is, and the SPF record generator builds a clean record from your list of senders.

Frequently asked questions

Can I ask receivers to allow more than 10 lookups?

No. The limit is part of RFC 7208 and there’s no tag to raise it. A receiver that happens to be lenient doesn’t help you with the ones that aren’t.

Does include count as one lookup no matter what’s inside?

No. The include itself counts as one, and every include, a, mx, ptr, exists and redirect inside the included record counts too, all the way down.

Does SPF permerror mean my mail is rejected?

Not necessarily. For DMARC it’s a fail, so mail still passes if DKIM passes and aligns. Without aligned DKIM, mail can go to spam or be rejected under p=quarantine or p=reject.

Is there a limit on the number of ip4 entries?

Not on lookups, since ip4 and ip6 are free. The practical limit is size: long records need splitting into 255-character strings, and very large DNS answers can cause problems for some resolvers.

Why did my SPF record go over 10 without me changing it?

A provider you include added nested includes to its own record. Your count depends on records other companies control, so check it periodically and keep a few lookups spare.