Appearance
SPF (Sender Policy Framework)
SPF is an email authentication protocol that specifies which mail servers are authorized to send email on behalf of your domain.
How SPF Works
The Problem
Without SPF, anyone can send email claiming to be from your domain. There's no way for receiving servers to know if the sender is legitimate.
The Solution
SPF allows you to publish a list of authorized senders in DNS:
example.com. TXT "v=spf1 include:_spf.google.com -all"When a receiving server gets an email "from" your domain:
- It looks up your SPF record in DNS
- It checks if the sending server is authorized
- It passes or fails the email based on your policy
SPF Record Syntax
An SPF record consists of:
v=spf1 [mechanisms] [all-policy]Version Tag
Always starts with v=spf1 (required).
Mechanisms
Mechanisms define who is authorized to send:
| Mechanism | Description | Example |
|---|---|---|
ip4: | IPv4 address or range | ip4:192.0.2.0/24 |
ip6: | IPv6 address or range | ip6:2001:db8::/32 |
a | Addresses in the domain's A/AAAA records | a or a:mail.example.com |
mx | Addresses of the domain's MX hosts | mx or mx:example.com |
include: | Checks another domain's SPF record | include:_spf.google.com |
exists: | Passes if a DNS name exists | exists:%{i}._spf.example.com |
ptr | Reverse DNS match. Deprecated: don't use it | ptr |
SPF also has two modifiers:
| Modifier | Description | Example |
|---|---|---|
redirect= | Use another domain's SPF record instead. Ignored if the record has an all mechanism | redirect=_spf.example.com |
exp= | Explanation text for rejected senders | exp=explain._spf.example.com |
Qualifiers
Mechanisms can have qualifiers:
| Qualifier | Meaning | Result |
|---|---|---|
+ | Pass (default) | Authorized |
- | Fail | Not authorized |
~ | SoftFail | Probably not authorized |
? | Neutral | No opinion |
All Policy
The all mechanism at the end defines the default policy:
| Policy | Meaning | Recommendation |
|---|---|---|
-all | Fail: senders not listed aren't authorized | Recommended once your record is complete |
~all | Soft fail: probably not authorized, usually accepted | A step while you confirm your senders |
?all | Neutral: no statement | Not recommended |
+all | Pass: anyone may send | Never use this |
Example Records
Basic - Google Workspace Only
v=spf1 include:_spf.google.com -allMultiple Services
v=spf1 include:_spf.google.com include:_spf.salesforce.com include:mail.zendesk.com -allOwn Mail Server + Services
v=spf1 mx ip4:203.0.113.0/24 include:_spf.google.com -allThe Include Tree
When SPF uses include:, the included domain's SPF is evaluated recursively. This creates an "include tree":
example.com
└── include:_spf.google.com
├── include:_netblocks.google.com
│ └── ip4:35.190.247.0/24 (and more)
├── include:_netblocks2.google.com
│ └── ip4:64.18.0.0/20 (and more)
└── include:_netblocks3.google.com
└── ip4:66.102.0.0/20 (and more)MailShield visualizes this tree to help you understand your SPF configuration.
DNS Lookup Limit
SPF is limited to 10 DNS lookups per check (RFC 7208, section 4.6.4), counted across all nested includes. Going over the limit makes SPF return permerror, which DMARC treats as a fail.
These count as DNS lookups:
include:amxptrexists:redirect=
These don't:
ip4:andip6:all
Void Lookups
A lookup that returns no records (the name doesn't exist, or has no records of that type) is a void lookup. RFC 7208 tells receivers to allow at most 2 per check; after that, SPF returns permerror too. Void lookups usually come from includes of services you no longer use, or typos in host names.
Avoiding the Limits
- Remove unused includes, and audit them regularly
- Use IP ranges instead of host names for your own servers
- Move services to subdomains with their own SPF records
- Flatten with care: replacing includes with IP ranges works, but breaks when a provider changes its IPs
Common Issues
Too Many DNS Lookups
Problem: The record needs more than 10 DNS lookups.
Symptoms:
- SPF returns
permerrorfor every message, which DMARC counts as a fail - Mail fails DMARC unless DKIM passes and aligns
Solutions:
- Remove unused includes and mechanisms
- Move some services to a subdomain
- Flatten includes to IP ranges, and keep them up to date
Multiple SPF Records
Problem: More than one TXT record at the domain starts with v=spf1.
Symptoms:
- SPF returns
permerrorfor every message (RFC 7208, section 4.5), so SPF fails everywhere
Solution:
- Merge everything into a single record
- Delete the duplicates
Record Too Long
Problem: A single TXT string can hold at most 255 characters.
Solution:
- Split a longer record into several quoted strings in the same TXT record. Receivers join them without spaces, so split between mechanisms and keep the spaces:
"v=spf1 include:_spf.google.com " "include:sendgrid.net -all" - Keep the whole record short: RFC 7208 recommends that the DNS answer fits in 512 bytes, so it doesn't need a fallback to TCP
Syntax Errors
Problem: Invalid SPF syntax.
Common mistakes:
- Missing
v=spf1 - Typos in mechanism names
- Invalid IP ranges
Solution:
- Validate with MailShield or other tools
No All Mechanism
Problem: Record doesn't end with all.
Impact:
- Neutral result for unauthorized senders
- Reduced protection
Solution:
- Add
-allor~allat the end
SPF and Email Forwarding
SPF can break when email is forwarded because:
- Original sender passes SPF
- Email is forwarded by another server
- Forwarding server's IP isn't in sender's SPF
- SPF fails at final destination
Solutions:
- Rely on DKIM: an aligned DKIM signature usually survives forwarding, and DMARC passes when DKIM passes
- Forwarders can use SRS (Sender Rewriting Scheme) so SPF checks their own domain
- Some receivers accept ARC (Authenticated Received Chain) results from trusted forwarders
Changing DMARC alignment doesn't help here: the forwarding server isn't in your SPF record, whatever the alignment mode.
SPF Alignment for DMARC
For DMARC, SPF must "align" with the From header:
Relaxed alignment (default):
- Envelope domain can be a subdomain of From header domain
mail.example.comaligns withexample.com
Strict alignment:
- Domains must match exactly
Best Practices
Do
✅ Use -all for hard fail in production
✅ Test with ~all before enforcing
✅ Monitor DNS lookup count
✅ Include all legitimate sending services
✅ Audit and remove unused includes regularly
Don't
❌ Use +all (allows everyone)
❌ Use deprecated ptr mechanism
❌ Exceed 10 DNS lookups
❌ Have multiple SPF records
❌ Forget about third-party senders \
Testing Your SPF
With MailShield
- Add your domain to MailShield.
- Open Checks → SPF to see the record, the include tree and the DNS lookup count.
- For any domain, including ones you don't monitor, use the SPF Checker.
Manual Testing
bash
# Look up SPF record
dig +short TXT example.com | grep spf
# Check from command line
nslookup -type=txt example.comProvider Includes
The SPF includes for common providers, and the ones that don't need an include at all, are listed in Third-Party Senders.