SPF sender policy framework: how the DNS check works

SPF (Sender Policy Framework) is a DNS-based email authentication method defined in RFC 7208. A domain owner publishes a DNS TXT record listing the mail servers authorized to send using that domain's address in the SMTP transaction. When a message arrives, the receiving mail system checks the sending server against that record and returns one of seven results, including pass, fail, or softfail. SPF authenticates the envelope sender domain, not the visible From address a recipient reads.
At a glance
Quick takeaways
- SPF records publish only as DNS TXT records that start with exactly
v=spf1; a domain with more than one matching record breaks the check with a permerror result, per RFC 7208. - A receiver checks the RFC5321.MailFrom (envelope sender) domain, and separately checking the HELO/EHLO domain is recommended; an empty MAIL FROM, as in a bounce, falls back to checking
postmasterat the HELO domain. - Each mechanism in the record carries a qualifier that sets its result:
+for pass,-for fail,~for softfail,?for neutral. The qualifier defaults to+when omitted. - A record with no
allmechanism and noredirectmodifier still returns neutral for unmatched senders, the same as an implicit?all. - DNS-querying mechanisms (
include,a,mx,ptr,exists) and theredirectmodifier are capped at 10 lookups total; going over the limit forces a permerror rather than a soft failure. - SPF checks the envelope sender, not the visible From address; DMARC only credits an SPF pass when the checked domain aligns with the visible From domain, per RFC 7489.
How the SPF check works
This page covers the RFC 7208 mechanics behind SPF. For the full topic cluster, see the SPF hub.
SPF version 1 works because a domain owner publishes, in DNS, which hosts are allowed to use that domain's name during the SMTP transaction, specifically in the HELO/EHLO identity and the MAIL FROM (envelope sender) identity. A receiving mail server compares the connecting IP address against that published record during the mail transaction, before the message is fully accepted, per RFC 7208, Section 1.
The record itself is published only as a DNS TXT (type 16) resource record. A verifier keeps only the record that begins with exactly v=spf1, and a domain must not publish more than one such record; if a lookup returns more than one, that is an error condition, not something the check merges together.
RFC 7208 requires a verifier to check the MAIL FROM identity whenever a HELO check was not performed or was not definitive, and it recommends checking HELO separately as well. Because MAIL FROM can be empty (a bounce or delivery-status notification uses a null reverse path), SPF defines that case explicitly: the checked identity becomes postmaster at the HELO domain instead.
Evaluation walks through the record's mechanisms in order and stops at the first match. Each mechanism carries a qualifier that determines the result once it matches:

Seven results are defined in total: none, neutral, pass, fail, softfail, temperror, and permerror. A pass is an explicit statement that the client is authorized to use the domain; fail is an explicit statement it is not; softfail is a weaker statement that the host is probably not authorized, without asking a receiver to reject outright, per RFC 7208, Section 2.6.
When the result changes
No match and no redirect
If none of a record's mechanisms match and the record has no redirect modifier, the result is neutral, exactly as though the record ended with an implicit ?all. A record that lists authorized senders but never adds all does not fail unmatched senders on its own; it simply returns neutral for them.
The include mechanism only counts a pass
The include mechanism runs a full, recursive evaluation of another domain's SPF record. Only a pass from that nested check makes include itself match. A fail, softfail, or neutral result from the included domain does not match at all; evaluation just moves to the next mechanism. A temperror from the included domain propagates up, and a permerror or none result turns the whole check into permerror.
The 10-lookup limit
Implementations must limit the mechanisms and modifiers that require a DNS query, meaning include, a, mx, ptr, exists, and the redirect modifier, to 10 total per evaluation, and must return permerror once that limit is exceeded. ip4, ip6, all, and exp do not count toward the limit because they need no additional lookup. A single mx mechanism has its own sublimit too: it must not query more than 10 address records, or the check also returns permerror. Implementations should also cap "void" lookups, meaning a query that returns no answer or NXDOMAIN, at two; exceeding that is another route to permerror. The ptr mechanism should not be published in a record at all, per RFC 7208, Section 5.5.
SPF pass is not DMARC alignment
A pass result authenticates the RFC5321.MailFrom domain, the envelope sender, not the RFC5322.From domain a person reads. DMARC only credits that pass when the two domains align: in relaxed mode they need only share the same organizational domain (for example, bounces.yourdomain.com aligns with yourdomain.com); in strict mode they must match exactly, per RFC 7489, Sections 3.1 and 3.1.2. A message can pass SPF outright and still fail DMARC if the envelope sender domain and the visible From domain do not align.
A worked SPF record
A record combining several common mechanisms looks like this:
yourdomain.com. IN TXT "v=spf1 ip4:203.0.113.0/24 include:_spf.provider.example -all"This is an illustrative example only; do not publish it as-is. Read left to right:
v=spf1identifies the record as SPF version 1; nothing else in the TXT value is evaluated unless this exact prefix is present.ip4:203.0.113.0/24matches, with the default+(pass) qualifier, any connecting IP inside that block, the domain's own mail servers.include:_spf.provider.exampleruns a nested check against an email provider's own record and matches only if that check returns pass.-allis the final mechanism, and it always matches. With a-qualifier, any sender not already matched by an earlier mechanism gets an explicit fail.
~all returns softfail instead of fail for unlisted senders, and ?all returns neutral. Because evaluation stops at the first match, mechanism order matters. Putting -all before include:_spf.provider.example would fail that provider's mail before its own record is ever checked.
Check your own record before changing it
A record that looks correct in isolation can still leave real senders unauthenticated. Before editing a live SPF record, build an inventory of everything that currently sends as the domain, including any transactional or marketing platform, help desk tool, or internal relay, then confirm each one is covered by an ip4, ip6, a, mx, or include mechanism.
Google's sender guidelines require SPF or DKIM from every sender and, for anyone sending 5,000 or more messages a day to Google, both SPF and DKIM with DMARC layered on top; unauthenticated mail at those volumes might be marked as spam or rejected with a 5.7.26 error, and the sending domain or IP still needs valid forward and reverse (PTR) DNS, per Google's email sender guidelines. That threshold is a useful floor for checking whether a record actually covers production mail, not just what was true when it was first written.
A DNS lookup only shows what a domain publishes. It cannot confirm that every application on the network actually sends through an authorized path, and it cannot show DMARC alignment by itself. Pair the SPF result with the domain's DKIM and DMARC configuration, covered in the broader email authentication stack. For a real-world example of a receiver treating SPF and DKIM as a hard requirement rather than a suggestion, see will La Poste require SPF, DKIM and DMARC for all senders?
Check the record before you rely on it
Reading the RFC does not tell you what a specific domain currently publishes, and a record edited months ago can drift from what actually sends mail today.
Run the domain through the SPF checker to see the published record, how its mechanisms parse, and whether it stays within the 10-lookup limit before changing anything.
A checker result confirms what DNS currently publishes. It does not confirm that every sending application uses an authorized path, and it does not replace a DMARC aggregate report for seeing which sources actually pass or fail in production.
Evidence
Sources and further reading
Questions readers ask
Frequently asked questions


Written by
Samuel ChenardCEO & Co-Founder, Palisade
Samuel Chenard is the CEO and co-founder of Palisade, AI-first DMARC software for IT teams and MSPs, from one domain to thousands.
More from Samuel →


