The SPF 10-lookup limit explained

An SPF check may run at most 10 terms that need a DNS query, and every include inside an included record counts too. Go past 10 and the check stops with a permanent error (permerror) instead of a pass, so SPF no longer vouches for your mail and some receivers reject it. The usual cause is one include per sending service, each pulling in more includes of its own. The fixes are to remove what you no longer use, move services to their own subdomains, list your own servers by IP address, and flatten only with care.

What counts toward the limit

RFC 7208, section 4.6.4 names the terms that make the receiver query DNS while it evaluates your record, and requires receivers to stop at 10 of them:

TermCounts toward 10?
include:Yes, plus every lookup inside the included record
a, mxYes
ptrYes (and it should not be used at all)
exists:Yes
redirect=Yes, plus the lookups in the record it points to
ip4:, ip6:No
allNo
exp=No (its lookup happens later, only to build an error text)

Two sub-limits sit on top of the main count. An mx term counts once, but the mail hosts it returns may lead to at most 10 address (A or AAAA) lookups, or the term itself returns permerror. A ptr term has the same cap of 10, though there the extra names are ignored instead of causing an error. Section 5.5 says ptr should not be published at all: it is slow, less reliable when DNS has errors, and it loads the reverse DNS servers.

The void lookup limit

The same section adds a smaller limit. A void lookup is a query that returns no records, or a reply that the name does not exist. Receivers should allow only two and return permerror on the third. A stale a: or mx: term that points at a retired host name is one way to collect them.

Other ways to get permerror

The lookup limits are not the only route to a permanent error. RFC 7208 also returns permerror when:

Section 8.7 calls permerror a condition that needs the DNS operator to step in. Retrying will not fix it.

How to count your lookups

Count every lookup term in your own record, then open each include and redirect target and count its terms too, all the way down. Take this record:

example.com.  TXT  "v=spf1 ip4:192.0.2.10 include:_spf.mail.example.net include:spf.crm.example.org mx -all"

Microsoft's SPF setup guide gives the same arithmetic: an include whose record holds three more includes adds four lookups in total. It also explains why an over-limit record can fail only some of the time. Receivers read the record from left to right and stop at the first match, so mail from a server listed early can still pass, while mail from a server listed late fails, and the bounce may say the message required too many lookups. A few passing messages prove nothing.

The SPF checker follows every include for you and shows the total number of lookups.

Why vendor includes add up

Every service that sends as your domain asks for its own include:: the mailbox provider, the newsletter tool, the CRM, the help desk, the billing system. That is what include is for: pointing at servers run by independent organizations (RFC 7208, section 5.2). But each included record is maintained by its vendor and may be a chain of further includes, so a vendor that adds one to its own record can push you over the limit without any change on your side.

How to get back under 10

Remove includes you no longer use

Start with an inventory of what really sends as your domain. Microsoft recommends a DMARC reporting service for finding your mail sources (DMARC aggregate reports). Delete the includes of services you have stopped using, and a or mx terms for hosts that no longer send.

Also check which domain each service puts in the envelope sender (the Return-Path header of a message it sent). SPF checks that domain, not the From: address people see. A service that uses its own bounce domain is checked against its own SPF record, so your include for it never comes into play for that mail. Before you delete such an include, make sure the service signs with DKIM for your domain, so that DMARC can still pass.

Move services to subdomains

Give each service you do not run yourself a subdomain, such as news.example.com for the newsletter. Each subdomain has its own SPF record and its own budget of 10 lookups. Microsoft recommends this for bulk mail services, partly to keep their reputation separate from your staff's mail. The subdomain needs its own record, because the record of example.com does not cover it.

example.com.       TXT  "v=spf1 ip4:192.0.2.10 include:_spf.mail.example.net -all"
news.example.com.  TXT  "v=spf1 include:spf.newsletter.example.org -all"

This keeps DMARC working. Under DMARC's default relaxed alignment, a bounce domain like news.example.com aligns with a From: address at example.com, because both share the organizational domain (RFC 9989, section 4.4).

List your own servers by IP address

ip4: and ip6: cost no lookups. For servers you control, RFC 7208 (section 10.1.1) calls a record that lists the addresses directly the best option and mx the expensive one. Section 10.1.2 names the trade-off: a and mx let you renumber hosts without touching SPF, at the cost of a lookup for every receiver. Unless your addresses change often, list them.

SPF flattening and its risks

Flattening replaces an include: with the IP addresses the included record lists today. The lookups are gone, but your record now holds a copy nobody updates for you: when the vendor changes its sending addresses, mail from the new ones fails SPF until you notice.

Microsoft's guide limits flattening to vendors with stable, documented address ranges, and says not to flatten services whose sending addresses change often, its own Microsoft 365 include among them. If you flatten anyway, it asks you to document what you replaced and when, watch the vendor's announcements, review the entries at least quarterly and test SPF after each change.

Flattened records also get long. RFC 7208 (section 3.4) advises keeping the record small enough that the DNS answer fits in 512 octets, roughly 450 octets for the name and records together, because larger answers can be silently ignored by some receivers. A single record can be split into several quoted strings of up to 255 octets each, which receivers join without spaces (section 3.3).

Let DKIM carry DMARC

DMARC passes when either SPF or DKIM passes for a domain aligned with the From: address (RFC 9989, section 4.4). Mail that is signed with DKIM for your domain still passes DMARC on a day when SPF breaks, so setting up DKIM for each service is the safer long-term fix. See DKIM selectors and key rotation.

One record per domain

A domain must not publish two SPF records (RFC 7208, section 3.2). When a new service tells you to "add this SPF record", merge its include: into the record you already have, before the final all. Two records starting with v=spf1 give every receiver a permerror, even if each record is fine on its own.

Every name that sends mail needs its own record, subdomains included. A domain that sends no mail at all should publish v=spf1 -all, which section 10.1.2 calls a well-established best practice. The SPF generator writes a single, merged record from the services you pick.

What the all qualifiers mean

The last term says what happens to a server the record does not list. Its prefix, the qualifier, decides the result (RFC 7208, sections 4.6.2 and 8):

EndingResultWhat receivers do with it
+all (or plain all)passAny server on the internet passes. Never publish it.
?allneutralTreated exactly like having no SPF record.
~allsoftfailProbably not authorized; receivers should not reject on this alone.
-allfailNot authorized; what happens next is the receiver's policy.

A record without any all ends in neutral, as if ?all were there (section 4.7). Terms after all are ignored, and so is a redirect= in the same record (section 5.1). Microsoft recommends -all once DKIM and DMARC are in place, and keeps ?all for testing only. Gmail's SMTP error list uses 550 5.7.26 for mail that fails SPF under a -all record, and 550 5.7.27 for a bulk sender's SPF failure. Other servers report a failed check as 550 5.7.23 and an SPF error, such as an over-limit record, as 5.7.24 (RFC 7372, section 3.2).

Questions

Can I split SPF into two TXT records to get more lookups?

No. Two SPF records are a permerror on their own, and the limit counts lookups across the whole evaluation, not per record. What you can split is one long record into several quoted strings inside a single TXT record. To get a fresh budget, use a subdomain.

Should I end with ~all or -all?

What happens next is up to the receiver. RFC 7208 says a softfail alone should not lead to a rejection, while a fail may. -all is the clearer statement once you are sure every service is listed. If you are still finding senders, ~all with DMARC reports is a reasonable step. See moving DMARC from none to reject.

Try it

Run your domain through the SPF checker to see the lookup total, and test an address you mail with the free email checker.

Sources

How we wrote this: drafted by the email-validation.org team with the help of AI writing tools, from our product documentation and the sources linked in the text.

Get up to 500 free credits. No card needed.

New accounts get 500 free credits (100 when you sign up with a free email provider such as Gmail, Outlook or Yahoo, or another personal mailbox such as a paid one like Fastmail or one from your internet provider). Try it on your own list before you buy.

Updated · Maintained by the email-validation.org team