SPFSender Policy Framework
SPF (Sender Policy Framework) is an email-authentication standard, defined in RFC 7208, that lets a domain owner publish a DNS TXT record listing exactly which mail servers are allowed to send on the domain’s behalf. A receiver compares the connecting server’s IP against that list to decide whether the message is authorised. It is one of the two checks DMARC relies on.
-
A single DNS
TXTrecord starting withv=spf1that lists authorised senders -
Checks the Return-Path (envelope) domain, not the visible
From:address -
Hard limit of 10 DNS lookups; exceeding it returns
PermErrorand breaks the check - SPF usually fails after a message is forwarded, which is why DKIM matters too
TXT (one per domain)
v=spf1
~all (softfail) or -all (fail)
How SPF works
SPF answers one question: is this server allowed to send mail for this domain? When a message arrives, the receiver reads the domain from the MAIL FROM command (the envelope sender, also called the Return-Path), looks up that domain’s SPF record in DNS, and checks whether the connecting IP address is on the authorised list. A match means SPF passes; if the record explicitly disavows that IP, SPF fails.
An important catch is that SPF checks the envelope domain, not the From: address your recipient actually sees. Those two can differ, which is exactly why SPF on its own cannot stop someone spoofing your visible From line, and why DMARC adds an alignment test on top. SPF also has a structural weakness: when a message is forwarded, the forwarding server becomes the new sending IP, which is almost never on the original domain’s SPF list, so the check fails. DKIM, which survives forwarding, exists to cover that gap.
Anatomy of an SPF record
An SPF record is a single TXT record made of mechanisms (sources of mail) and an all term that catches everything else:
example.com. IN TXT "v=spf1 include:_spf.google.com ip4:203.0.113.10 ~all"
Mechanisms and qualifiers
The common mechanisms are:
ip4/ip6: authorise a specific address or CIDR range. These cost no DNS lookup.include: pull in another domain’s SPF record (how you authorise an ESP such as Google or SendGrid).a/mx: authorise the IPs behind the domain’s A or MX records.all: the catch-all at the end, applied to anything not already matched.
Each mechanism carries a qualifier that sets the result when it matches: + pass (the default), - fail, ~ softfail (accept but mark suspicious), and ? neutral. Almost every record ends in ~all or -all. The ptr mechanism still exists but the RFC says not to use it: it is slow and unreliable.
The 10-lookup limit
To protect DNS from abuse, RFC 7208 caps an SPF evaluation at 10 DNS-querying mechanisms. Only the terms that trigger a lookup count: include, a, mx, ptr, exists, and the redirect modifier. The ip4, ip6, and all terms are free. Crucially, an include counts every lookup inside the record it pulls in, so a couple of nested ESP includes can blow the budget fast.
Exceed 10 and the receiver returns PermError, which most treat as an authentication failure. The fix is “flattening”: replacing chained include statements with the underlying ip4/ip6 ranges so the lookup count drops, then keeping it maintained as those ranges change.
Why SPF matters for sender reputation
Since February 2024, Google and Yahoo require bulk senders (5,000 or more messages a day) to authenticate, and a valid SPF record is one of the accepted checks; Microsoft applied the same baseline to large Outlook and Hotmail senders in 2025. A missing, broken, or PermError SPF record is one of the most common reasons otherwise-legitimate mail lands in spam or is rejected outright.
For DMARC to pass, a passing SPF result must also align: the Return-Path domain it checked must share an organizational domain with your visible From:. Because many ESPs put their own domain in the Return-Path, SPF can pass yet fail DMARC alignment, which is why senders configure a custom Return-Path or lean on aligned DKIM. You can confirm what you have published with the SPF checker.
How an SPF check runs
MAIL FROM envelope domainv=spf1 TXT recordall
-all: fail
~all: softfail
+: pass
From: can satisfy DMARCSPF vs DKIM
| SPF | DKIM | |
|---|---|---|
| What it checks | The sending IP is authorised | A valid signature from the domain |
| Mechanism | DNS list of IPs | Cryptographic signature + DNS key |
| Identity used | Return-Path / envelope | The d= signing domain |
| Survives forwarding? | Usually no | Usually yes |
| Setup | One DNS TXT record | Key pair + signer + DNS key |
By the numbers
PermError.v=spf1 records are a configuration error.Common mistakes
v=spf1 TXT record. Two of them make the result PermError, failing every SPF check. Merge all authorised sources into a single record.include statements quietly pushes you past 10 DNS lookups, returning PermError with no bounce. Audit the count and flatten chained includes into ip4/ip6 ranges.+all+all authorises the entire internet to send as your domain, which is worse than having no record. End in -all or ~all.From:. That requires DMARC alignment on top of SPF.Frequently asked questions
v=spf1, lists the servers allowed to send for your domain, and ends with an all term, for example v=spf1 include:_spf.google.com ~all. The include mechanisms authorise email providers, ip4/ip6 authorise specific addresses, and the qualifier on all (~ softfail or - fail) sets what happens to everything else.PermError), publishing more than one SPF record, leaving out a sending service such as your ESP or CRM, or the message being forwarded so the sending IP is no longer on your list. Run an SPF lookup, count your includes, and confirm every legitimate source is authorised.include, a, mx, ptr, exists, and redirect terms, while ip4, ip6, and all are free. Each include also counts the lookups inside the record it references, so nested includes add up quickly.