SPF Record Checker and Validator
Enter a domain and we will show its SPF record, expand the full include chain and count the DNS lookups. A record that is not published yet goes into the Record text tab, where it gets the same analysis. If the record breaks the RFC limit or lets anyone send as you, we say so and tell you what to change.
What an SPF record does
SPF (Sender Policy Framework, RFC 7208) is a list of servers you have authorised to send mail on behalf of your domain, published as a TXT record in DNS. When a message reaches a receiving mail server, it checks the IP address the connection came from against your SPF record and decides whether that address is on the list.
The domain being checked is not the From address the reader sees. It is the envelope domain from the MAIL FROM command, also known as the Return-Path. Bounce notifications have an empty envelope, and for them the server name from the HELO greeting is checked instead. SPF does not require the From domain to match the checked one; that is DMARC's job.
Records need re-checking well after the initial setup, because they decay. You add another sending service and cross the lookup limit; a provider changes its IP ranges; someone publishes a second TXT record without noticing the first. In every one of those cases the DNS panel looks perfectly normal while validation on the receiving side fails.
Check a published record or a draft
The Domain tab goes to DNS and parses what is published there right now. The Record text tab parses the string you paste, which may not exist in DNS yet. One answers "what does this domain have", the other "will the thing I am about to publish fly". The analysis behind both is the same, and in both cases includes are expanded with real DNS queries: counting the budget requires knowing what sits inside other people's records today.
Pasting is handy for a draft before publishing, for a record from a new vendor's guide (does one more include still fit?), and for whatever a contractor proposes. Paste only the value, the string that starts with v=spf1. The record name, type and TTL from your DNS panel are not needed, and surrounding quotes are stripped automatically. The Domain field on that tab only matters when the record uses a or mx without an explicit host, because otherwise there is no way to tell whose A and MX records are meant.
The expanded chain and the lookup counter
Alongside the record itself you get the expanded chain. Every include points at another domain's SPF record, which may contain includes of its own, and all of it counts towards one shared limit. The counter shows how many of the ten allowed lookups are already spent, and the mechanism table marks which terms cost one.
The total is what matters most. The closer it gets to ten, the greater the chance that some service adds an include to its record and yours breaks without you touching anything. It is also worth scanning the domains in the chain: one you do not recognise is probably left over from a service you dropped a year ago, and it can still send mail as you.
SPF record syntax: mechanisms and qualifiers
A record opens with v=spf1, followed by space-separated mechanisms, and usually ends with all. Receivers read them left to right and stop at the first match, so anything written after all has no effect.
v=spf1 ip4:203.0.113.5 include:_spf.google.com ~allThis allows 203.0.113.5 and everything listed in Google Workspace's SPF record. Every other sender gets softfail.
ip4andip6name an address or a network.ip4takes only IPv4 with a prefix up to /32,ip6only IPv6 with a prefix up to /128, and a single address needs no prefix. Neither costs a DNS lookup.aandmxallow the addresses in the domain's A and MX records. Convenient, but each costs a lookup, and after a hosting move the record will quietly start authorising a different machine.includepulls in another domain's record, usually a sending service. If that domain has no SPF record, the whole evaluation ends in permerror rather than just losing one service.existsis rare, andptrshould not be published at all according to RFC 7208: it is slow and unreliable when DNS misbehaves.redirect=andexp=are modifiers. The first hands evaluation to another domain's record when no mechanism matched, the second sets the explanation text for a failure. Receivers skip modifiers they do not know, but an unknown mechanism breaks the record.
A mechanism can carry a qualifier: + allows (and is assumed when there is no sign), - denies, ~ denies softly, ? asserts nothing.
The 10 DNS lookup limit
RFC 7208 allows at most ten lookups per evaluation. They are spent by include, a, mx, ptr, exists and the redirect modifier, and nested records count towards the same total. ip4, ip6 and all are free. Past ten, evaluation returns permerror and SPF does not pass, however correct the record looks.
The budget usually runs out around the third or fourth service: an ESP, a CRM and a helpdesk each bring several nested includes. We suggest keeping two or three lookups in reserve. Eight or nine technically pass, but the record will break as soon as any connected service expands its infrastructure, and nobody will warn you when that happens.
When the reserve is gone, start by removing includes for services you no longer use. If that is not enough, the remaining ones can be expanded into explicit ip4 and ip6 ranges, as described in the SPF flattening guide. Flattened addresses then need watching: when a service changes its IPs, your record will not know.
The third way is to split sending across subdomains, so that campaigns carry, say, news.example.com in the envelope and support mail carries help.example.com. Each subdomain gets its own SPF record and its own budget of ten lookups.
What the final mechanism means
-all, fail. Mail from anywhere else may be rejected. The right destination, with one caveat below, but move there once DMARC reports confirm every one of your senders is accounted for.~all, softfail. The message is accepted but marked. A sensible setting while you are still configuring.?all, neutral. Receivers learn nothing useful.+allauthorises everyone. Worse than no record: the domain looks configured while standing wide open to forgery.- No mechanism at all. Without a
redirecteither, the result is neutral, the same as?all.
RFC 9989 adds a caveat about -all. Some receivers run SPF before DMARC and reject during the SMTP session. A valid DKIM signature that would have let the message pass DMARC does not save it, and the message never shows up in DMARC aggregate reports either.
Pass, fail, softfail and the other four SPF results
RFC 7208 defines seven outcomes. The receiving server records them in the Received-SPF and Authentication-Results headers, so the headers of a specific message show how its check went.
- pass: the IP address is in the record.
- fail: the domain explicitly forbids sending from this address.
- softfail: probably not allowed, without a hard refusal.
- neutral: the domain asserts nothing.
- none: there is no SPF record, or no domain could be taken from the session.
- temperror: a transient DNS error; a later retry may succeed.
- permerror: the record could not be interpreted. It will not go away on its own; the DNS has to be fixed.
Common mistakes
- Two v=spf1 records. More on this in the next section.
- More than ten DNS lookups. Typically after one more service gets connected.
- An include pointing at a domain with no SPF record. Usually a typo in the name. That mechanism breaks the whole evaluation.
- An example copied along with somebody else's domain. A line like
include:_spf.example.compasted verbatim is syntactically flawless and passes validation, yet it authorises infrastructure you have nothing to do with. Take include values from your own service's documentation rather than from articles: they change. - A broken address. A
/33prefix inip4, an IPv6 address insideip4, an address missing its last octet. Receivers return permerror. - Includes for services you no longer use. They consume lookups and leave authorisation with someone who should not have it.
- The ptr mechanism, or no all. The first is deprecated; without the second the record forbids almost nothing.
- A long record in a single string. One TXT string holds 255 characters. Longer records are split into several quoted strings, which receivers join without adding spaces, so the space between two mechanisms has to stay inside one of the strings.
Two SPF records on one domain
This is the most common breakage, and it has nothing to do with syntax. The standard allows a domain exactly one record starting with v=spf1. With two, evaluation returns permerror and SPF stops working entirely, not partially.
The usual story goes like this. Mail is set up through the hosting provider, which adds a record. Then a sending service is connected, its guide says "add a TXT record", and the second one lands next to the first. Each looks correct on its own.
The fix is to merge them into one string: every include from both records goes into one, duplicates are removed, and a single all remains. Before publishing, paste the result into the Record text tab to confirm it stays within the lookup limit.
What a correct record looks like
For a domain that sends only through its own mail server:
v=spf1 mx -allFor Google Workspace plus a marketing platform:
v=spf1 include:_spf.google.com include:spf.example-esp.com ~allThe record is published as a TXT record on the root of the domain (name @). Subdomains do not inherit it: if campaigns go out from mail.example.com, that name needs its own record.
SPF, DKIM and DMARC
On its own, SPF does not stop spoofing. An attacker passes SPF with their own domain in the envelope and puts yours in the From header, and the recipient sees your address. DMARC closes that gap with alignment: the From domain has to match a domain that passed SPF or DKIM. That is why the three records are set up together, step by step in the SPF, DKIM and DMARC setup guide. Forwarding is another reason to have DKIM: it breaks SPF by design, while a DKIM signature usually survives if the message is not altered on the way. Signatures are checked in the DKIM checker, policies in the DMARC checker.
What this check cannot tell you
A syntactically correct record can still be substantively wrong. We have no idea which services you use, so we will not flag a leftover include from something you abandoned, nor a missing one for something you just connected. Only DMARC aggregate reports settle that: they list the actual sources sending as your domain, with the SPF outcome for each. The gap between that list and your record is the real configuration error.
So re-check the record after every change, and every few months for no particular reason. The contents of other people's includes change whenever their provider adds servers, and a record that fitted the limit yesterday can exceed it today.
Sources
- RFC 7208, section 2.4: which domain SPF checks
- RFC 7208, section 2.6: evaluation results
- RFC 7208, section 3.3: records made of several strings
- RFC 7208, section 4.6.4: DNS lookup limits
- RFC 7208, section 5: mechanisms
- RFC 7208, section 6: modifiers
- RFC 9989, section 7.1: SPF and the order of DMARC checks
SPF questions
Read next
Domain configured but mail still not arriving?
Half of all deliverability problems live in the list, not in DNS: dead addresses, spam traps, disposable mailboxes. uChecker cleans your list before you send, and the first 100 addresses are free.
Check your list