Skip to content
DMARC Done

spf

SPF too many DNS lookups: the 10-lookup limit and how to fix it

Why SPF breaks after 10 DNS lookups, how to count yours, and how to get back under the limit without cutting off a service that sends your email.

DMARC Done team · 5 October 2026 · 6 min read

If a checker tells you your SPF record needs “too many DNS lookups”, your SPF record is broken for some receivers right now, even though it looks fine. This post explains the limit, shows you how to count your own lookups, and walks through the fixes in order from safest to riskiest.

What SPF does, in one paragraph

SPF (Sender Policy Framework) is a TXT record at the root of your domain that lists which servers may send email for it. It starts with v=spf1 and ends with an all rule. A receiving server reads it, works out whether the sending server is on the list, and passes or fails the message. SPF is defined in RFC 7208.

A typical record for a business on Microsoft 365 that also uses two other services looks like this:

v=spf1 include:spf.protection.outlook.com include:mail.vendor-a.example include:send.vendor-b.example -all

Each include: says “also accept whatever servers this other domain lists”. That is convenient, and it is also where the trouble starts.

The 10-lookup limit

To find out which servers are allowed, the receiver has to look things up in DNS. Every include: means at least one more DNS query, and the included record can contain its own includes.

To stop this from turning into an endless chain, RFC 7208 (section 4.6.4) caps it. The terms that cause DNS queries are the include, a, mx, ptr and exists mechanisms and the redirect modifier. Receivers must limit the total number of those terms to 10 during one SPF check. If the limit is exceeded, the result is permerror, a permanent error.

The same section sets a second, smaller limit: receivers should allow no more than two “void lookups”, meaning lookups that return no answer. An include: pointing at a domain that no longer publishes SPF counts as one of those.

What permerror does to your email

A permerror is not a pass. What happens next depends on the receiver:

  • Some reject the message outright. Microsoft describes bounce messages with errors such as “The message required too many lookups.”
  • Others treat it like an SPF failure and lean on DKIM instead.

For DMARC (Domain-based Message Authentication, Reporting and Conformance, the policy layer on top of SPF and DKIM), an SPF permerror means SPF cannot help that message pass. If the message also has a valid DKIM signature that matches your domain, DMARC can still pass on DKIM alone. If it does not, the message fails DMARC. Once you move to p=quarantine or p=reject, that failed message goes to spam or bounces.

Microsoft also points out a nasty detail: receivers evaluate the record from left to right and stop at the first match. So a record with too many lookups can work for mail that matches an early entry and fail only for mail that matches a late one. That is why the problem often shows up as “some of our invoices bounce” rather than “all email is broken”.

How to count your lookups

Count one for each of these in your record: include:, a, mx, ptr, exists: and redirect=. These are free and never count: ip4:, ip6: and all.

Then open every include: and count what is inside it, because nested terms add up. Microsoft gives the arithmetic: an include: that points to a record containing three more includes costs four lookups in total, one for the first lookup and three for the nested ones.

A quick worked example with placeholder vendors:

v=spf1 mx include:mail.vendor-a.example include:send.vendor-b.example -all
  • mx: 1
  • include:mail.vendor-a.example: 1, and its record contains two more includes: +2
  • include:send.vendor-b.example: 1, and its record contains one a term: +1
  • -all: 0

Total: 6. Under the limit, but only four more includes away from breaking.

Counting by hand gets tedious fast, and vendors change their records without telling you. The free checker at /check?d=yourdomain.com follows every include, counts lookups and void lookups the way RFC 7208 does, and shows the total.

Plain-English takeaway: SPF allows 10 DNS lookups per check, nested includes included. Go over and SPF returns a permanent error, which some receivers treat as a failure. Count your lookups, then remove what you do not use before trying anything clever.

How to fix it, safest first

1. Remove services you no longer use

This is the fix that works most often. SPF records grow over the years: an old newsletter tool, a previous email host, a website plugin from a redesign two years ago. Nobody removes them because nobody remembers why they were added.

Before you delete anything, find out what really sends mail as you. DMARC aggregate reports are the best evidence: they list every server that sent mail using your domain, with message counts. If a service has not appeared in a month of reports, its include is a strong candidate for removal. If you have no DMARC record yet, start with our post on publishing your first DMARC record.

2. Remove terms that do nothing

  • ptr: RFC 7208 says this mechanism “SHOULD NOT be published”. It is slow and unreliable. Remove it.
  • a and mx: these authorize your website’s server and your incoming mail servers. If your website does not send mail and your inbound mail is handled by Microsoft 365 or Google Workspace, they may add lookups for nothing. Check before removing, because some website contact forms do send through the web server.
  • Duplicates: the same include written twice still costs twice.

3. Ask each vendor whether they need your SPF at all

SPF checks the envelope sender (the hidden bounce address, also called MAIL FROM), not the From address your customers see. Some email services send with their own bounce address, or with a subdomain of yours that you point at them, and rely on DKIM for DMARC. If a vendor works that way, its include in your root record costs you lookups and does nothing. Their setup documentation usually says which records they need.

4. Move bulk senders to a subdomain

Microsoft recommends sending marketing or bulk email from a subdomain such as news.yourdomain.com. Each subdomain has its own SPF record and its own 10-lookup budget. It also keeps a marketing tool’s reputation problems away from your main domain.

5. Flattening, with care

“Flattening” means replacing an include: with the IP addresses it currently resolves to, written as ip4: and ip6: entries. IP entries cost no lookups, so the count drops.

The trade-off is maintenance. The vendor can change its sending IP addresses at any time. Your flattened record will not notice, and mail from the new addresses will start failing SPF with no warning. Microsoft’s guidance is specific:

  • Flattening can suit vendors with stable, documented IP ranges.
  • Do not flatten Microsoft 365’s include:spf.protection.outlook.com, because its sending addresses change frequently.
  • If you flatten, record what you replaced, watch vendor announcements and review the entries at least quarterly.

Automated flattening services update the IPs for you. That solves the staleness problem but makes your SPF depend on another company’s uptime. For most small businesses, steps 1 to 4 get the count under 10 without any of this.

Two other SPF errors that look similar

  • Two SPF records. Only one TXT record starting with v=spf1 is allowed per domain. Two records produce permerror as well. Merge them into one.
  • Syntax slips. Microsoft lists common ones: a trailing dot after the domain, include= instead of include:, or a space after the colon.

After the fix

Run the checker again and confirm the lookup count is 10 or less and the void lookup count is 2 or less. Then keep an eye on DMARC reports for a week: if a legitimate service starts failing SPF, you removed something it needed.

A clean SPF record is also a prerequisite for moving DMARC to enforcement. If you want someone else to untangle your senders and take the domain all the way to p=reject, see pricing.

Sources

See where your domain stands in 10 seconds

Free. No signup. We do not store the domains you check.