Anyone can put any domain they want in an email's "From:" field — SMTP, the protocol email runs on, was never designed to stop that. SPF (Sender Policy Framework) is the mechanism that lets a domain owner publish, in DNS, exactly which mail servers are actually allowed to send mail claiming to be from that domain — so a receiving server can check a claim against a public, authoritative list instead of just trusting it. This post covers how that check actually works, what a valid record looks like, and the mistakes that quietly break it.
What a receiving server actually checks
When a mail server receives an incoming message, it looks at the envelope sender — the address used in the SMTP MAIL FROM command, sometimes visible later as the Return-Path header — extracts its domain, and looks up that domain's SPF record via a DNS TXT query. It then checks whether the IP address the connection is actually coming from is authorized by that record. If it is, SPF passes; if not, the result depends on the record's policy (more on qualifiers below).
The detail worth sitting with: the envelope sender and the visible "From:" header a recipient actually sees are two different fields, checked completely independently. SPF only ever validates the envelope sender. This is exactly why passing SPF is not the same as "this email is definitely genuine" — the visible From address a person actually reads can still be forged even when SPF passes cleanly, which is the whole reason DMARC (covered near the end) exists to tie the two together.
Anatomy of an SPF record
An SPF record is a DNS TXT record whose value starts with the literal version tag v=spf1, followed by a space-separated list of terms:
v=spf1 include:_spf.google.com ip4:203.0.113.0/24 -allEach term after the version tag is either a mechanism (a rule that matches or doesn't match the sending server) or a modifier (extra metadata, written as name=value). Every mechanism can be prefixed with a qualifier that determines what result that mechanism produces when it matches:
+— Pass (the default when no qualifier is written at all — a bareallmeans the same thing as+all).-— Fail. The receiver should reject or clearly flag mail from a source this matches.~— SoftFail. A weaker signal — most receivers accept the mail but treat it as more likely to be spam or forged.?— Neutral. Explicitly says "no opinion," treated the same as having no SPF record at all for this specific source.
Mechanisms are evaluated left to right, and evaluation stops at the first match — order matters. A record ending in -all means "if nothing above matched, fail everything else," which is why all almost always appears last.
The mechanisms, one by one
- all — matches everything. Always the catch-all at the end of a record.
- include:domain — pulls in another domain's SPF record and matches if that record would produce a Pass. This is how you authorize a third-party sender (Google Workspace, a marketing platform, a transactional email API) without listing their actual server IPs, which they can change without notice.
- a / mx — matches if the sending IP matches the domain's A/AAAA record, or one of its mail servers' addresses, respectively.
- ip4:address / ip6:address — matches a specific address or CIDR range directly, with no DNS lookup required to evaluate.
- ptr:domain — matches via reverse DNS. RFC 7208 explicitly discourages this one: it's slow, depends on reverse DNS being configured correctly (which it often isn't), and is considered legacy.
- exists:domain — matches if a DNS A record lookup for the given (often macro-constructed) domain returns any result at all — a flexible, less common mechanism used for custom validation logic.
Two modifiers exist alongside mechanisms: redirect=domain points evaluation at another domain's entire SPF record as a fallback (only used if nothing else in the record already matched), and exp=domain supplies a custom explanation string for Fail results — rare in practice.
The 10-lookup limit
RFC 7208 caps the number of DNS lookups a single SPF evaluation may perform at 10. include, a, mx, ptr, exists, and the redirect modifier each cost one lookup; ip4, ip6, and all cost nothing, since they're evaluated directly against the data already in the record. Crucially, this limit applies to the entire chain: every include pulls in another record that may itself contain more lookup-costing terms, and they all count against the same shared limit of 10.
Exceeding it isn't a soft warning — RFC 7208 requires receivers to stop and return a PermError, which generally fails SPF entirely for that message. A domain that adds one third-party sender too many, each contributing its own handful of nested lookups, can silently cross this limit and start failing SPF for messages from servers that are genuinely authorized — a real, common, and easy-to-miss failure mode, since nothing about the record looks obviously wrong by eye.
Common mistakes
- +all, or a bare all. Marks literally every sending server on the internet as authorized — the single most damaging SPF misconfiguration, since it makes the record actively worse than having none, giving anyone who checks SPF false confidence.
- No all mechanism at all. Without one, a message from an unlisted source gets a Neutral result rather than a clear Fail — rarely the intended behavior once a record is meant to be a real policy rather than a work-in-progress draft.
- Publishing more than one SPF TXT record. A domain must have exactly one. Adding a new provider's recommended record without removing or merging into the existing one is one of the most common real-world SPF breakages — the result is a PermError, not "both records apply."
- Quietly exceeding the 10-lookup limit as more third-party services get added over time, each contributing an
include— covered in depth above. - Combining redirect with an explicit all. Since evaluation stops at the first match and
allalways matches, aredirectplaced alongside anallin the same record can never actually be reached.
SPF records don't inherit to subdomains
A common assumption: publish SPF on example.com and mail.example.com is automatically covered too. It isn't — SPF checks the exact domain used in the envelope sender, so each subdomain that actually sends mail needs its own SPF TXT record. A subdomain with no SPF record of its own gets a Neutral result (or, depending on receiver policy, sometimes treated more strictly), not the parent domain's policy. This trips people up specifically when a subdomain starts sending mail through a new service — a marketing platform on news.example.com, say — and nobody remembers it needs a record independent of the main domain's.
Rolling out a new or changed record safely
Changing an existing SPF record carries real risk: get it wrong and legitimate mail starts failing. The safer sequence is to publish with ~all (SoftFail) first rather than jumping straight to -all (Fail) — SoftFail lets you monitor how mail from every actual sending source is being evaluated without outright rejecting anything while you confirm the record is complete. Only after confirming every legitimate sender is accounted for (mail server logs, or DMARC aggregate reports if DMARC is already configured, are the two most direct ways to check) does it make sense to tighten to -all. Skipping straight to a strict policy on a freshly written record is how an overlooked sending source — an old CRM integration, a forgotten transactional email provider — quietly starts failing without anyone noticing until a customer reports a missing email.
SPF is one layer, not the whole system
SPF validates a connecting server against an IP-based allowlist for the envelope sender domain — nothing more. DKIM takes a different, complementary approach: the sending server cryptographically signs each message, and the receiver verifies that signature against a public key published in DNS, which also (unlike SPF) survives the message being forwarded through an intermediate server. DMARC sits on top of both: it tells receivers what to do when SPF and/or DKIM fail, and — critically — ties the whole check back to the visible "From:" domain a recipient actually sees, which SPF and DKIM alone don't directly protect. A domain serious about stopping spoofing needs all three configured together, not SPF in isolation.
FAQ
Does passing SPF mean an email definitely isn't spoofed?
No — SPF only checks the invisible envelope sender (the MAIL FROM address used during SMTP delivery), not the visible "From:" address a recipient actually sees. A message can pass SPF cleanly while still showing a forged display name and From address, which is exactly why SPF is meant to work alongside DMARC, not alone.
What's the difference between an SPF checker and an SPF validator?
In practice, none — both terms describe the same task: checking whether a record is syntactically valid and free of the mistakes (missing all, exceeding 10 lookups, duplicate records) that cause receivers to reject or ignore it.
Why do so many SPF records include Google, Microsoft, or Mailgun?
Because most organizations send mail through a third-party service (Google Workspace, Microsoft 365, a transactional email API) rather than running their own mail server — including that provider's SPF record authorizes their sending infrastructure without needing to know or maintain the actual IP addresses behind it, which the provider can change without you having to update anything.
Can I test what my SPF record actually resolves to without waiting for real email?
Yes — DNS lookup tools show the live TXT record for a domain, and pasting that text into an SPF parser checks its syntax and lookup count immediately, without needing to send or receive any actual mail.
Does SPF protect against phishing?
Only partially, and only for spoofing of your own domain specifically — it can't stop a lookalike domain, a compromised legitimate account, or a phishing email that doesn't try to impersonate your domain's envelope sender at all. It's one layer of a defense that needs DKIM and DMARC alongside it to meaningfully cover the visible sender address.
Try it yourself
SPF Record Parser — an SPF checker, parser, and validator in one — breaks down any SPF TXT record into its mechanisms and qualifiers, counts its direct DNS lookups against the 10-lookup limit, and flags every mistake covered in this post, entirely in your browser. For securing the website side rather than the email side, see HTTP Security Headers Explained.