SPF (Sender Policy Framework) is a TXT record at the domain that lists the servers allowed to send mail using that domain in the envelope sender (MAIL FROM).
google.com. 273 IN TXT "v=spf1 include:_spf.google.com ~all"
; SPF policy: 2 terms, 1 include, ends with ~all
github.com. 10 IN TXT "v=spf1 ip4:192.30.252.0/22 include:spf.protection.outlook.com include:_netblocks.google.com include:_netblocks2.google.com include:mail.zen ... 69.170 ip4:166.78.71.131 ~all"
; SPF policy: 14 terms, 8 includes, ends with ~all
microsoft.com. 2279 IN TXT "v=spf1 include:_spf-a.microsoft.com include:_spf-b.microsoft.com include:_spf-ssg-a.msft.net include:_spf1-meo.microsoft.com -all"
; SPF policy: 5 terms, 4 includes, ends with -all
example.com. 300 IN TXT "v=spf1 -all"
; SPF policy: 1 term, 0 includes, ends with -all
The receiving server takes the domain from the SMTP MAIL FROM address (or HELO name), fetches its v=spf1 TXT record and evaluates the terms left to right against the connecting IP. The first mechanism that matches decides the result, using its qualifier: + pass (the default), - fail, ~ softfail, ? neutral.
SPF was briefly given its own record type (99), but RFC 7208 deprecated it: publish SPF only as TXT. Evaluation may cause at most 10 DNS-querying terms (include, a, mx, ptr, exists, redirect); going over is a permerror. SPF checks the envelope sender, not the visible From header. DMARC adds that link through alignment.
example.com. 3600 IN TXT "v=spf1 ip4:192.0.2.0/24 include:_spf.google.com -all"
Wire format: Stored as an ordinary TXT record at the domain itself. The TXT strings are joined before parsing.
| Field | Meaning |
|---|---|
| v=spf1 | Version. Must be the first term, and there must be only one SPF record per name. |
| ip4 / ip6 | Authorizes an address or CIDR range. No DNS lookup. |
| a / mx | Authorizes the addresses of the domain's A/AAAA or MX hosts. One lookup each (plus up to 10 for the MX names). |
| include: | Evaluates another domain's SPF; a pass there is a match here. Used for email providers. |
| exists: | Matches if a constructed name resolves; used with macros. |
| redirect= | Replaces this record with another domain's if nothing else matched. |
| all | Matches everything. Put it last: -all or ~all. |
v=spf1: a permerror, which receivers treat as a failure.+all or ?all, which authorize or ignore every server on the internet.