What it is
SPF (Sender Policy Framework, RFC 7208) is a TXT record at your domain that lists which servers may send mail using that domain in the envelope sender (the MAIL FROM, which becomes the Return-Path header). Receiving servers look it up for every message and get a result such as pass, fail or softfail. SPF does not check the visible From: header; tying the two together is the job of DMARC.
example.com. 3600 IN TXT "v=spf1 include:_spf.google.com ip4:203.0.113.10 ~all"
The syntax
The record starts with v=spf1, followed by mechanisms evaluated left to right; the first one that matches decides.
| Term | Matches | DNS lookup? |
|---|---|---|
ip4:203.0.113.0/24, ip6:2001:db8::/32 |
The sending IP is in this range | No |
a, a:mail.example.com |
The IP is one of that name's A/AAAA addresses | Yes |
mx |
The IP is one of the domain's MX hosts | Yes |
include:_spf.google.com |
That domain's SPF record passes | Yes |
exists:, ptr |
Rarely used; ptr is discouraged by the RFC |
Yes |
redirect=other.example |
Use another domain's record instead (modifier) | Yes |
all |
Everything else | No |
Each mechanism can take a qualifier: + pass (the default), - fail, ~ softfail, ? neutral. So -all says "reject anything not listed", ~all says "probably not us, accept but mark it", and +all authorises the whole internet and should never be published.
~all or -all? With DMARC enforced, receivers act on DMARC, and many treat the two the same. ~all is the safer default while you are still finding all your senders; move to -all once your DMARC reports show every legitimate source passing.
Common setups
- Google Workspace:
v=spf1 include:_spf.google.com ~all - Microsoft 365:
v=spf1 include:spf.protection.outlook.com -all - Both plus a newsletter tool: one record with every include, for example
v=spf1 include:_spf.google.com include:sendgrid.net ~all. - A domain that sends no mail:
v=spf1 -all, ideally with a DMARCp=reject.
How to check it
The SPF checker expands every include and counts lookups; the email authentication check shows SPF, DKIM and DMARC together. From a terminal:
dig +short TXT example.com
nslookup -type=TXT example.com
Common mistakes
- Two SPF records. A domain must have exactly one TXT record starting with
v=spf1. Two of them is apermerrorand SPF fails for every message. Merge them into one. - More than 10 DNS lookups.
include,a,mx,ptr,existsandredirecteach count, including those inside nested includes;ip4,ip6andalldon't. Past 10 the result ispermerror. Remove unused services, replacea/mxwithip4ranges where stable, or drop a vendor include you no longer use. There is also a limit of 2 lookups that return nothing ("void" lookups). - Strings over 255 bytes. A long record must be split into several quoted strings in the same TXT record; they are joined with no space, so put the space inside a string.
- Using the SPF record type. DNS type 99 (SPF) is obsolete; publish TXT only.
- Expecting SPF to survive forwarding. A forwarder sends from its own IP, so SPF fails; DKIM survives and lets DMARC still pass.
Related record types
- DKIM record: signs the message itself.
- DMARC record: policy and alignment on top of SPF and DKIM.
- MX record: where your inbound mail goes, which
mxrefers to. - TXT record: the record type SPF lives in.