---
title: "SPF Record Checker: Lookup Count and Errors"
url: "https://lookvalid.com/tools/spf-record-checker.md"
canonical_url: "https://lookvalid.com/tools/spf-record-checker"
last_updated: "2026-10-19"
type: "tool"
summary: "Check any domain's SPF record for free. See how many of the 10 allowed DNS lookups it uses, the full include tree, what the closing qualifier means."
related: ["https://lookvalid.com/docs/api/email-domain-check.md"]
---

# SPF Record Checker: Lookup Count and Errors

Check any domain's SPF record for free. See how many of the 10 allowed DNS lookups it uses, the full include tree, what the closing qualifier means.

Enter a domain to read its SPF record and every record it includes. You get the number of DNS lookups used out of the 10 that RFC 7208 allows, the chain of domains that were read, what the ending of the record means in plain words, and whatever would make SPF fail.

## Facts

- Free, no account needed. The domain you type goes from your browser to a public DNS resolver run by Cloudflare, with Google as the backup. It does not pass through LookValid, and this page stores nothing.
- Related API product: [email-domain-check](https://lookvalid.com/docs/api/email-domain-check.md), 1 credit through the API.

## How it works

1. Type a domain. A pasted link or email address is cut down to its domain name.
2. Your browser asks a public DNS resolver for the TXT records at that domain, keeps the one that starts with v=spf1, then reads every include and redirect it names, counting each term that costs a DNS lookup.
3. The page shows lookups used out of 10, empty lookups, the policy for servers not listed, every domain that was read and anything that needs fixing.

## Example result

Domain github.com, read through Cloudflare's DNS over HTTPS on 2026-10-19. Captured 2026-10-19.

- Verdict: SPF record found, 10 of 10 lookups used
- SPF records found: 1 (320 characters, stored as 2 strings and joined without a space)
- Policy for other servers: ~all (softfail)
- DNS lookups used: 10 of 10: 8 in the record itself, 1 inside _spf.salesforce.com and 1 inside sendgrid.net
- Empty lookups: 0 (more than 2 is an error)
- Includes: spf.protection.outlook.com, _netblocks.google.com, _netblocks2.google.com, mail.zendesk.com, _spf.salesforce.com, servers.mcsv.net, mktomail.com, sendgrid.net, ab.sendgrid.net
- Domains read: 10: github.com and the nine includes above
- Note: One term, exists:%{i}._spf.mta.salesforce.com, depends on the sender. It is counted and not followed.

## Why 10 lookups is the limit that matters

A receiving mail server has to ask DNS a question for every include, a, mx, ptr and exists term in an SPF record, and for the redirect modifier. RFC 7208 section 4.6.4 caps that total at 10 across the whole tree, counting the records that includes lead to. At 11 the result is a permanent error, and SPF fails for every message from the domain.

The terms ip4, ip6 and all need no DNS query and are never counted. An mx term counts once however many mail servers the domain has, but the RFC also says an mx term that leads to more than 10 mail server names is an error. Each include also brings in everything inside the included record, which is why one extra service can push a record over the limit without anyone editing it: the vendor changes its own record and your count rises.

Lookups that come back empty, because the name does not exist or has no data of the type asked for, are counted separately. The RFC recommends stopping at two of these, and the checker reports the third as an error.

## The two failures nobody sees

Going over 10 lookups and publishing two SPF records at the same name both end in a permanent error. Neither one shows up when you send a test message to yourself, because many receivers fall back to other signals. The damage appears as mail landing in spam, or being refused, at the receivers that follow the standard strictly.

Two records are not merged. A resolver can return them in any order, so the outcome is not meaningful either way. The fix is one record that holds every term. If you need to keep a long list of senders, use fewer includes or replace stable ones with ip4 and ip6 terms, and keep an eye on those addresses, because a vendor's addresses can change.

## What the ending of the record means

-all (fail): mail from any server not listed is rejected or marked as failing. ~all (softfail): mail from other servers is accepted but marked as suspicious, and most receivers send it to spam. ?all (neutral): nothing is said about other servers. +all (pass): every server may send as the domain, which makes the record useless. A term written with no sign in front of it carries a plus.

When a record ends in redirect= instead of all, the policy is the one at the domain it points to, and the checker reports it from there. A redirect is ignored when the same record also has all.

## SPF is about who may send, and MX is about who receives

SPF lists the servers allowed to send mail that claims to come from a domain. The servers that receive mail for the domain are named in its MX records, which the MX record lookup can show you. A domain can be fully set up for sending and still be unable to receive, and the other way around.

## How the count is made

The checker counts every term that evaluation could reach, because it does not know which server will be tested. A receiving server stops at the first term that matches the sender, so its own count for a given message can be lower. A record that is over the limit here is over the limit for at least some senders.

Terms that depend on the sender through a macro, such as exists:%{i}.example.com, cannot be run without a sender address. They are counted and listed, and not followed. Nesting stops at 10 levels, and a record that includes itself, directly or through other records, is reported as a loop.

## SPF terms and which ones cost a DNS lookup

| Term | What it does | Counts toward the limit of 10 |
| --- | --- | --- |
| include:domain | Applies the SPF record of another domain and counts as a match if that record passes. Everything inside the included record counts too. | Yes, one |
| a, a:domain | Matches the address records of the domain (or the named one). | Yes, one |
| mx, mx:domain | Matches the mail servers listed in the MX records of the domain (or the named one). | Yes, one in total, however many mail servers it names |
| ptr | Matches by reverse DNS name. The RFC says it should not be used: it is slow and unreliable. | Yes, one |
| exists:domain | Matches when the named domain has any address record. Usually written with a macro. | Yes, one |
| redirect=domain | Uses the SPF record of another domain as the policy when no term has matched. Ignored when the record has all. | Yes, one |
| ip4:range | Matches an IPv4 address or range. | No |
| ip6:range | Matches an IPv6 address or range. | No |
| all | Matches every sender. Written last, with a sign in front that sets the policy. | No |
| exp=domain | Names a record that holds the text of the rejection message. Read only after a message has failed. | No |

## Sources

- [RFC 7208: Sender Policy Framework, section 4.6.4 DNS lookup limits](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4), read 2026-10-19
- [RFC 7208, sections 3.3 and 3.4: multiple strings and record size](https://www.rfc-editor.org/rfc/rfc7208#section-3.3), read 2026-10-19
- [RFC 7208, section 4.5: selecting records (more than one record is a permanent error)](https://www.rfc-editor.org/rfc/rfc7208#section-4.5), read 2026-10-19
- [Cloudflare 1.1.1.1 documentation: DNS over HTTPS, using JSON](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-json/), read 2026-10-19
- [Google Public DNS: DNS over HTTPS JSON API](https://developers.google.com/speed/public-dns/docs/doh/json), read 2026-10-19

## Questions

### What happens when an SPF record needs more than 10 lookups?

RFC 7208 says the receiver must return a permanent error. SPF then fails for the domain, and what a receiver does with a failing result depends on its own policy and on your DMARC record. The usual fixes are to remove services you no longer send through, replace includes with ip4 and ip6 terms for senders whose addresses do not change, or send each service from its own subdomain with its own record.

### Is it allowed to publish more than one SPF record on a domain?

No. Two or more records that start with v=spf1 at one name make the check fail with a permanent error, as RFC 7208 section 4.5 specifies. Merge their terms into one record. A record for a subdomain is a different name and is fine.

### Should my record end in -all or ~all?

With -all, mail from an unlisted server should fail. With ~all, it is accepted but treated as suspicious. Many domains begin with ~all while they confirm every legitimate sender is listed, then tighten to -all.

### Why does the checker say it could not finish?

The DNS resolver did not answer in time or reported a server failure for one of the names. That says nothing about whether the record exists, so the checker does not call it missing. Run it again in a moment.

### Is the count here the same as the count a mail server will make?

It is the highest count any sender could cause, because every reachable term is counted. A receiver stops at the first term that matches the sender, so for a given message its count can be lower. Terms that depend on the sender through a macro are counted and not followed.

### Does this tool send my domain anywhere?

Your browser sends the domain, and the names found inside its record, to a public DNS resolver, Cloudflare first and Google if Cloudflare cannot be reached. Nothing goes to LookValid and nothing is stored.

## Related

- [Email Domain Check reference](https://lookvalid.com/docs/api/email-domain-check.md)
