Short answer: SPF allows at most 10 DNS-lookup terms (include, a, mx, ptr, exists and redirect, nested ones included) and at most 2 void lookups; going over either limit makes SPF return PermError, which receivers treat as broken SPF. Enter your domain below to see every lookup in order with a running count, plus duplicates, terms after “all” and a trimmed record. If trimming is not enough, the tool also builds a minimally flattened record, which you must keep up to date because flattened IP addresses go stale.
We tested this tool on 6 October 2026 by running its code in a test harness on our lab server (AlmaLinux 9.8, PHP 8.2) against live DNS: google.com, microsoft.com, outlook.com, salesforce.com, mailchimp.com, example.com, and draft records built to trigger each problem (nine sender includes adding up to 15 lookups, void lookups, an include loop, duplicates, terms after “all” and a null MX). The flattened record it suggested was checked again and came back at 10 lookups. The dig commands on this page were run on the same server.
How to use the SPF lookup counter
- Type the domain that appears after the @ in your From address, for example
example.com. Do not includehttps://or a path. - Click Count lookups. The tool reads the TXT records of the domain, picks the one that starts with
v=spf1and follows every include and redirect the same way a receiving mail server does. - To test a change before you publish it, paste the new record into Draft SPF record. The tool evaluates the draft as if it were published on that domain, so you can add a new sender and see the new count first.
- Fix what the results point to, wait for the TTL of the TXT record to pass, and run the check again.
Terms are counted the way RFC 7208 counts them. Each include, a, mx, ptr, exists and redirect costs one lookup, and the terms inside an included record count as well. ip4, ip6, all and exp cost nothing. A receiver stops at the first term that matches the sending IP, but the limit applies to the worst case: a message from a server that matches nothing makes the receiver walk the whole record, so the tool counts every term.
Reading the results
The summary at the top answers the main question. DNS lookups shows the total against the limit of 10; 9 or 10 is shown as a warning because one more sender breaks SPF. Void lookups counts terms whose DNS query returned no answer or NXDOMAIN; RFC 7208 recommends a limit of 2. Result tells you whether receivers will see a valid record or a PermError, and why.
The Lookup tree table lists every term in the order a receiver evaluates it. The Count column is a running total, so you can see exactly which include pushes the record past 10. Nested records are indented under the include that pulls them in, and an include that costs more than one lookup says how many it costs in total. Address ranges inside a record are summarised in one line per record, because they do not cost lookups.
| Row in the tree | What it means |
|---|---|
VOID LOOKUP | The name in an a, mx, include or exists term has no records. The term never matches but still costs a lookup, and more than 2 of them is a PermError. |
duplicate | The same domain is included twice, often directly and again through another include. Both copies count. |
ignored: comes after "all" | Receivers stop at all, so anything after it is dead text. A redirect= is also ignored in any record that has an all. |
uses SPF macros | Terms such as exists:%{i}._spf.example.net are built from each message. They cost one lookup but cannot be followed without a real sender IP. |
null MX | The target publishes MX 0 . (RFC 7505), meaning it accepts no mail. An mx term pointing there costs a lookup and never matches. |
deprecated (ptr) | RFC 7208 says not to use ptr. It is slow, depends on reverse DNS the sender controls, and still costs a lookup. |
Below the tree, Suggested trimmed record appears when something can be removed without changing who is allowed to send: duplicate includes, ranges already covered by a wider range, terms after all, a redirect next to all, and terms that can never match. Trimming adds no maintenance, so try it first.
Flattened record appears only when the trimmed record still needs more than 10 lookups. The tool replaces the most expensive includes with the address ranges they resolve to today, one include at a time, and stops as soon as the count is 10 or less, so as few includes as possible are frozen. Includes that use macros, exists, ptr or non-pass qualifiers are never flattened.
Flattened addresses go stale. Google, Microsoft, Mailgun and other senders change their IP ranges without telling you, and mail from a new range fails SPF until you update the record. Only publish a flattened record if you will re-check it on a schedule, and prefer the fixes below.
Check a record yourself with dig
To see the raw record a receiver gets, query TXT records from any Linux server. On our lab server this returned the published record for example.com:
dig +short TXT example.com
"v=spf1 -all"
Follow an include by querying the domain it names, for example dig +short TXT _spf.google.com. Windows has nslookup -type=TXT example.com. If the answer contains two strings that both start with v=spf1, receivers return PermError before they count anything.
Common problems and fixes
Too many DNS lookups (more than 10)
- Remove includes for services you no longer use. Old newsletter tools, helpdesks and CRMs are the usual leftovers.
- Replace
aandmxwithip4:andip6:when the servers are your own and their addresses rarely change. That saves one lookup each. - Move bulk or marketing mail to a subdomain such as
news.example.comwith its own SPF record. Each domain gets its own 10 lookups. - Check whether a provider offers a smaller include. Some publish one include per region or product, so you only need the one you use.
Void lookups
A void lookup usually means a typo in an include, a provider that retired an SPF hostname, or an a: term for a server that no longer exists. Delete the term or correct the name. An include that points to a name without any SPF record is a PermError even if it is the only void lookup.
Duplicates and terms after all
Remove the second copy of a duplicate include, and move all to the end of the record. These fixes never change who may send, so the trimmed record shown by the tool is safe to publish as-is once you have checked it.
Record longer than 255 characters
A single TXT string holds 255 characters. Longer records are split into several quoted strings inside one TXT record, which receivers join without spaces; most DNS panels split them for you. RFC 7208 section 3.4 suggests keeping the whole answer under about 450 bytes so it fits in one UDP packet. Flattened records grow quickly, which is another reason to flatten as little as possible.
Official documentation: RFC 7208: SPF (section 4.6.4, DNS lookup limits) · RFC 7505: Null MX
Related: SPF Record Checker · SPF Record Generator · DMARC Checker · SPF, DKIM and DMARC in cPanel DNS: Setup and Checks · Microsoft 365 SPF DKIM DMARC: Secure Exchange Online Setup
See also: SPF Too Many DNS Lookups: Fix PermError and the 10-Lookup Limit · DNS TXT Record Splitter: Split Long Values Into 255-Byte Strings
Frequently asked questions
What happens when SPF has more than 10 DNS lookups?
The receiver stops evaluating and returns PermError. Most receivers then treat SPF as failed or missing, so DMARC can only pass if DKIM passes and aligns.
Do ip4 and ip6 count toward the 10-lookup limit?
No. Only include, a, mx, ptr, exists and the redirect modifier count, including the ones inside included records. ip4, ip6, all and exp do not.
What is a void lookup in SPF?
A term whose DNS query returns NXDOMAIN or an empty answer, such as an include for a name that does not exist. RFC 7208 recommends a limit of two; more is a PermError.
Is SPF flattening safe?
Only if you keep it updated. Flattening copies a provider’s current IP ranges into your record, and when the provider changes them your mail starts failing SPF. Trim first, and move senders to subdomains before you flatten.
Why is my count different from another SPF checker?
Checkers handle edge cases differently, such as terms after all, macros, null MX or includes that fail. This tool follows RFC 7208, shows every term it counted in the lookup tree, and counts the worst case, which is what decides PermError.