SPF lists the servers allowed to send mail for a domain. The record is easy to break: a second SPF record, too many includes or a typo turns every check into a PermError. This checker walks the full include tree the way a receiving server does.
Table of Contents
The 10-lookup limit
Every include, a, mx, ptr, exists and redirect costs a DNS lookup, and nested includes count too. Over 10 lookups the result is PermError, which Gmail and Microsoft treat much like a fail. Remove services you no longer use, replace a and mx with ip4 ranges where possible, or send marketing mail from a subdomain with its own SPF.
End the record with ~all or -all. ?all protects nothing and +all authorises the entire internet to send as you.
SPF record checker at a glance



How to use this tool
- Enter the domain to check. For mail you send, that is the domain in the Return-Path (envelope sender), which is usually the same as the From domain for mailboxes and often a different domain or subdomain for newsletter and CRM platforms.
- Press Check SPF. The tool reads the TXT records of the domain, picks the one that starts with
v=spf1, and then follows everyinclude:andredirect=recursively, the way a receiving server does. - Read the four summary lines (record, DNS lookups, void lookups, default policy), then open the include tree to see where the lookups come from.
- To test a draft before you publish it, paste it into the SPF lookup counter. To build a new record, use the SPF record generator.
How to read the results
| Field | What it means |
|---|---|
| SPF record | The record found at the domain. “Not found” means receivers get the SPF result none: they cannot tell which servers may send for the domain. |
| DNS lookups | Terms that cost a DNS query, counted through the whole tree: include, redirect, a, mx, ptr and exists. ip4, ip6 and all are free. Green below 8, amber from 8 to 10, red above 10 (PermError). |
| Void lookups | Lookups that returned nothing. The tool counts an include or redirect target without an SPF record and an mx term on a domain without MX records. RFC 7208 recommends a limit of two; green at 0, amber at 1 or 2, red above 2. |
| Default policy | The qualifier on all in the top-level record: -all hard fail and ~all soft fail are fine, ?all neutral protects nothing, and +all (or a bare all) lets anyone send as you. Not shown when the record ends with redirect= instead of all. |
| Include tree | One row per domain visited, indented with a dash per level. Each row shows the SPF record found there, “no SPF record”, or “MULTIPLE SPF records (PermError)”. |
In the headers of a received message, the SPF result appears in the Authentication-Results line as one of seven values defined in RFC 7208:
| Result | Meaning |
|---|---|
| pass | The sending IP is authorised by the record. |
| fail | The IP is not authorised and the record ends with -all. |
| softfail | The IP is not authorised and the record ends with ~all. |
| neutral | The record makes no statement about this IP (?all). |
| none | No SPF record was found for the domain. |
| temperror | A temporary DNS failure, such as a timeout at the domain’s name servers. |
| permerror | The record cannot be evaluated: two SPF records, a syntax error, more than 10 lookups, or an include pointing at a domain without SPF. |
Common problems and how to fix them
“SPF record: Not found” although you added one
Check that the record is a TXT record (the separate SPF record type 99 is obsolete and ignored), that it sits on the domain itself and not on www, and that the value begins exactly with v=spf1 followed by a space. Some panels need the host field empty or set to @.
dig +short TXT example.com
# Windows
nslookup -type=txt example.com 1.1.1.1
Two SPF records on one domain
This happens often on cPanel servers when the panel created a record and a mail provider’s setup guide added a second one. Receivers return permerror for both. Merge every mechanism into one record and delete the other:
# before (two records = permerror)
v=spf1 +a +mx +ip4:203.0.113.10 ~all
v=spf1 include:spf.protection.outlook.com -all
# after (one record)
v=spf1 ip4:203.0.113.10 include:spf.protection.outlook.com -all
More than 10 DNS lookups (PermError)
The include tree shows which service uses the most lookups. Remove includes for services you no longer use, replace a and mx with the server’s ip4: address, and move bulk senders to a subdomain such as news.example.com with its own record. The step-by-step fix is in SPF too many DNS lookups.
A branch in the include tree says “no SPF record”
An include points at a domain that publishes no SPF record, usually a typo or a provider that retired that name. RFC 7208 treats an include whose target has no SPF record as permerror, so the whole record fails. Correct the name from the provider’s current documentation or remove the include.
Gmail: “has an SPF record with a hard fail policy (-all) but it fails to pass SPF checks”
Gmail rejected the message because the sending IP is not in your record and the record ends with -all. Find the sending IP in the bounce or in the Received headers (the email header analyzer extracts it), then add that server’s ip4: range or the provider’s include. Remember that SPF checks the Return-Path domain, so the record to fix may be on a bounce subdomain.
Forwarded mail fails SPF
When a server forwards a message, it sends it from its own IP while keeping your Return-Path, so SPF fails at the final destination. That cannot be fixed in your record. The forwarding server should rewrite the envelope sender with SRS, and your mail should carry a DKIM signature, which survives forwarding when the message is not modified. See SRS and strict forwarding errors.
A long record was split and now fails
A single TXT string holds at most 255 characters, so long records are published as several quoted strings. Receivers join them with no space in between, so a split like "v=spf1 include:_spf.google.com" "include:spf.protection.outlook.com -all" becomes ...google.cominclude:... and breaks. End each string with a space or split inside the value. The DNS TXT splitter does it safely.
What a good SPF record looks like
| Situation | Record |
|---|---|
| Mail only from one cPanel or DirectAdmin server | v=spf1 ip4:203.0.113.10 ~all |
| Microsoft 365 mailboxes plus website mail from the server | v=spf1 ip4:203.0.113.10 include:spf.protection.outlook.com -all |
| Google Workspace mailboxes plus website mail from the server | v=spf1 ip4:203.0.113.10 include:_spf.google.com ~all |
| Domain that never sends mail | v=spf1 -all (add a null MX and a DMARC record with p=reject) |
Keep these rules in mind: one record per domain name, only the services that really send with this domain in the Return-Path, ip4/ip6 instead of a and mx where you can, and no ptr. Subdomains do not inherit the parent’s record, so a subdomain that sends mail needs its own. Setup steps for the common panels are in SPF, DKIM and DMARC in cPanel DNS and, for Microsoft 365, Microsoft 365 SPF, DKIM and DMARC.
Official documentation: RFC 7208 (SPF), DirectAdmin documentation, cPanel & WHM documentation.
Related guides: Warm up a new mail server IP or sending domain without landing in spam · Choosing a VPS for a cPanel or DirectAdmin server in 2026 · Exim 4.99/4.100 on cPanel and DirectAdmin: the 2026 security fixes and what changed for admins.
Frequently asked questions
Can a domain have two SPF records?
No. Two TXT records starting with v=spf1 cause a PermError. Merge them into one record.
Should I use -all or ~all?
~all (soft fail) is the safer default while DMARC is at p=none; once DMARC enforcement is in place, -all adds little because DMARC already decides. Either is fine — never +all.
Do I need SPF if I have DKIM and DMARC?
Yes. Many receivers still check SPF, and DMARC passes when either SPF or DKIM passes with alignment, so having both makes delivery more robust.
What is an SPF void lookup?
A DNS lookup made while evaluating SPF that returns no records, for example an include of a domain without SPF or an mx term on a domain without MX. RFC 7208 recommends that receivers return permerror after more than two.
Do ip4 and ip6 count toward the 10-lookup limit?
No. Only include, redirect, a, mx, ptr and exists cause DNS lookups. ip4, ip6 and all are free, which is why replacing a and mx with IP ranges saves lookups.
Which domain does SPF check?
The domain in the envelope sender (Return-Path or MAIL FROM), and the HELO name. It does not check the visible From address; DMARC links the two through alignment.
Do subdomains inherit the SPF record of the main domain?
No. SPF is looked up on the exact domain in the envelope sender, so news.example.com needs its own record if it sends mail.
Why does the include tree say “no SPF record” for one of my includes?
The included domain publishes no SPF record, usually because of a typo or a retired provider name. That turns your whole SPF result into permerror, so fix or remove it.
Can an SPF record be longer than 255 characters?
Yes, by publishing it as several strings in one TXT record; receivers join them without spaces. RFC 7208 advises keeping the whole DNS answer under 450 bytes so it fits in a single UDP packet.