Deliverability
SPF Record Explained: Syntax, Examples, and Common Mistakes
An SPF record is a DNS TXT record that lists which servers may send email using your domain in the envelope sender (the “MAIL FROM” or Return-Path address). Receiving servers look it up, compare the connecting IP address against the list, and return a result such as pass, fail, or softfail. A typical record looks like v=spf1 include:_spf.google.com ~all, and each domain may publish only one.
This guide covers the syntax piece by piece, shows records for common setups, and walks through the mistakes that break SPF in practice.
What an SPF record does (and what it doesn’t)
SPF is defined in RFC 7208. It lets a domain owner authorize hosts to use the domain in two SMTP identities: the HELO/EHLO name and the MAIL FROM address. That second one is the address bounces go to, not the From address your recipient sees.
That distinction matters more than anything else in this article:
- SPF checks the envelope sender (also called Return-Path, bounce address, or 5321.MailFrom).
- SPF does not check the visible From: header (5322.From).
- Linking the two is DMARC’s job, through a concept called alignment. See DMARC alignment: strict vs relaxed.
So an SPF pass alone does not prove the message came from the brand in the From line. It proves the bounce domain authorized the sending IP. That’s still useful, and mailbox providers require it. Google’s sender guidelines say all senders must set up SPF or DKIM, and anyone sending more than 5,000 messages a day to Gmail must set up both.
SPF record syntax, piece by piece
Every SPF record has three parts: a version tag, a list of mechanisms, and usually a final all.
v=spf1 ip4:203.0.113.10 include:_spf.google.com include:amazonses.com -all
Receivers evaluate the terms left to right and stop at the first match.
The version tag
The record must start with exactly v=spf1. RFC 7208 says records that don’t begin with this tag are discarded, so v=spf2, v=SPF1 with odd spacing from a broken editor, or a leading quote character in the wrong place can make the whole record invisible.
Mechanisms
| Mechanism | What it matches | Costs a DNS lookup? |
|---|---|---|
ip4:203.0.113.10 or ip4:203.0.113.0/24 | A single IPv4 address or CIDR range | No |
ip6:2001:db8::/32 | IPv6 address or range | No |
a / a:mail.example.com | The A/AAAA records of the domain | Yes |
mx / mx:example.com | The IPs of the domain’s MX hosts | Yes |
include:_spf.example.net | Whatever the other domain’s SPF record authorizes | Yes |
exists:%{i}._spf.example.com | Matches if an A record exists for the built name | Yes |
ptr | Reverse DNS of the sender | Yes, and deprecated |
all | Everything | No |
The lookup column matters because RFC 7208 (section 4.6.4) caps the DNS-querying terms at 10 per evaluation. Go over and the result is a permanent error. We cover that in detail in SPF “too many DNS lookups”: how to fix it.
The ptr mechanism is officially “do not use.” RFC 7208 section 5.5 says it should not be published because it is slow and unreliable. If you see it in an old record, remove it.
Qualifiers
Each mechanism can carry a prefix that decides the result when it matches:
| Qualifier | Result | Typical use |
|---|---|---|
+ (default) | pass | Authorized senders; you almost never type it |
- | fail | -all at the end: everything else is unauthorized |
~ | softfail | ~all: everything else is probably unauthorized |
? | neutral | ?all: no opinion; testing only |
The all mechanism
all matches every IP, so it goes last as the default. Per RFC 7208 section 5.1, anything listed after all is ignored. If there is no all and no redirect, the default result is neutral, which tells receivers nothing.
Modifiers: redirect and exp
redirect=_spf.example.comhands the whole evaluation to another domain’s record. Useful when many domains share one policy. It counts as a DNS lookup and is ignored if the record also containsall.exp=points to an explanation string for rejections. Few senders use it.
SPF record examples for common setups
Use these as patterns, then check your provider’s documentation for the exact include value.
Google Workspace only. Google’s SPF setup page gives:
v=spf1 include:_spf.google.com ~all
Microsoft 365 only. Microsoft’s SPF configuration guide gives:
v=spf1 include:spf.protection.outlook.com -all
Your own server plus Microsoft 365. Add the server’s public IP:
v=spf1 ip4:203.0.113.10 include:spf.protection.outlook.com -all
A sending subdomain for Amazon SES. If you set a custom MAIL FROM domain such as bounce.example.com, AWS’s MAIL FROM documentation has you publish this on that subdomain, along with an MX record pointing to the regional feedback endpoint:
bounce.example.com. TXT "v=spf1 include:amazonses.com ~all"
bounce.example.com. MX 10 feedback-smtp.us-east-1.amazonses.com
A domain that never sends mail. Parked and defensive domains should say so:
v=spf1 -all
Microsoft’s guide uses this exact record for parked domains. Pair it with a DMARC p=reject record and a null MX (MX 0 .) for full coverage. See what is an MX record for the null MX format.
-all or ~all: which should you use?
This is the most common SPF question, and the two big mailbox providers publish different defaults:
- Google recommends
~allfor Workspace domains on its SPF setup page. - Microsoft recommends
-allfor Microsoft 365 domains. Its reasoning: DMARC treats both-alland~allas SPF failures, and-alllets DMARC act on messages that also lack a DKIM signature.
In practice, once you have DMARC deployed, the difference shrinks, because DMARC policy decides what happens to failing mail. A reasonable rule:
- Start with
~allwhile you inventory every service that sends as your domain. - Watch your DMARC aggregate reports for legitimate sources failing SPF. Our guide on reading DMARC aggregate reports shows how.
- Move to
-allonce the reports are clean, if your DMARC rollout calls for it.
Avoid +all. It authorizes the entire internet to send as you.
Common SPF record mistakes
Publishing two SPF records
RFC 7208 is explicit: a domain must not have multiple SPF records, and if a receiver finds more than one, the result is permerror. This usually happens when a second vendor’s setup wizard tells you to “add a TXT record” and you add a new one instead of editing the existing one. Merge them:
Wrong (two records):
v=spf1 include:_spf.google.com ~all
v=spf1 include:sendgrid.net ~all
Right (one record):
v=spf1 include:_spf.google.com include:sendgrid.net ~all
Exceeding 10 DNS lookups
Every include, a, mx, exists, and redirect counts, and nested includes count too. Microsoft’s guide notes that fewer than 10 include statements doesn’t guarantee fewer than 10 lookups, because each include can contain more includes. Count recursively, or use the SPF checker on this site.
Syntax typos
Microsoft’s troubleshooting table lists three classics, and we see them constantly:
- A trailing dot:
include:spf.protection.outlook.com. - An equals sign instead of a colon:
include=spf.protection.outlook.com - A space after the colon:
include: spf.protection.outlook.com
RFC 7208 section 4.6 says any syntax error causes an immediate permerror for the whole record, not just the broken term.
Too many void lookups
A “void lookup” is a DNS query that returns no records or NXDOMAIN, often from an include pointing to a vendor you stopped using. RFC 7208 says implementations should limit void lookups to two, and exceeding that is also a permerror. Remove includes for services you’ve cancelled.
Forgetting subdomains
Each hostname that appears in a MAIL FROM address needs its own SPF record. Microsoft’s documentation points out that the record on example.com does not cover marketing.example.com. SPF has no inheritance.
Records that are too long
A single TXT string is limited to 255 characters. RFC 7208 section 3.3 says a long record can be split into multiple strings, which receivers concatenate without adding spaces. So put the space inside the string:
"v=spf1 ip4:203.0.113.0/24 include:_spf.google.com " "include:amazonses.com -all"
Section 3.4 also recommends keeping the whole DNS response under 512 octets so it fits in a single UDP packet.
Using the ptr mechanism
Covered above: deprecated, slow, and some receivers effectively ignore it. Replace it with ip4/ip6 or the right include.
How to check your SPF record
From a terminal:
dig +short TXT example.com | grep spf1
On Windows PowerShell:
Resolve-DnsName -Type TXT example.com | Where-Object { $_.Strings -match "spf1" }
Then test the real thing. Send a message to a Gmail account, open it, choose “Show original,” and look for spf=pass in the Authentication-Results header. If you see spf=permerror, go back through the mistakes list above.
Gmail’s SMTP error reference shows what failures look like on the wire: 4.7.27 means mail was rate limited because SPF didn’t pass, and 5.7.27 means it was blocked for the same reason.
SPF is one third of authentication
SPF on its own breaks easily. Forwarding changes the connecting IP, so forwarded mail often fails SPF even when the original was fine (the existing post on ARC and forwarded mail covers why). DKIM survives forwarding better, and DMARC ties both to the visible From domain. If you’re setting things up from scratch, follow how to set up SPF, DKIM, and DMARC step by step.
One more practical note: authentication protects your domain, but it does nothing for the addresses you send to. If your list has typos and dead domains, you’ll still bounce. Run new addresses through our free email verifier to catch bad syntax, domains with no MX records, disposable domains, and common typos like gmial.com before they hit your sender reputation. It doesn’t log into mailboxes, but it removes the obvious failures for free.
FAQ
Can I have two SPF records on one domain?
No. RFC 7208 says a domain must not publish more than one SPF record, and receivers return permerror if they find two. Combine all your mechanisms into a single record that starts with v=spf1.
Should I use the SPF record type or TXT?
Use TXT. A dedicated SPF record type existed in the original experimental spec, but RFC 7208 discontinued it and says SPF records must be published as TXT. Some DNS dashboards still show an “SPF” option; ignore it.
Does SPF check the From address my recipients see?
No. SPF checks the envelope sender (Return-Path) and optionally the HELO name. The visible From address is tied to SPF only through DMARC alignment, which requires the two domains to match.
How long does an SPF change take to work?
It depends on the TTL of the old record. Microsoft recommends a TTL of at least 3,600 seconds (one hour) for SPF records, so expect changes to propagate within that window once caches expire. Test with a fresh message rather than an old one.
Do I need SPF if I already have DKIM?
Yes, if you send in volume. Google and Yahoo require both SPF and DKIM for bulk senders, and SPF also gives receivers a fast check before they process the message body.
Free email verifier: syntax, MX, disposable and role-based addresses, typos. Paste up to 100 at once.