Understanding SPF
SPF (Sender Policy Framework) is the first line of defence in email authentication. It tells the world which servers are allowed to send email for your domain. This guide goes beyond the basics — covering the DNS lookup limit, SPF flattening, common mistakes, and a complete reference of provider includes.
Why SPF matters
Every domain that sends email should have an SPF record. Without one, any server on the internet can send email claiming to be from your domain, and the receiving server has no way to check. SPF gives receivers a list of authorised senders, published in DNS, that they can verify in real time.
SPF is also a prerequisite for DMARC. When DMARC evaluates an inbound message, one of the checks it performs is whether SPF passed and whether the SPF-authenticated domain aligns with the visible From: address. Without a valid SPF record, half of DMARC's verification is missing.
How SPF DNS records work
An SPF record is a single DNS TXT record published at the root of your domain. It always begins with v=spf1 and ends with an all qualifier. Everything in between is a list of mechanisms that define who is allowed to send.
Basic syntax
v=spf1 [mechanisms...] [qualifier]allMechanisms
| Mechanism | What it does | Example |
|---|---|---|
include: | Authorises all IPs listed in another domain's SPF record | include:spf.protection.outlook.com |
ip4: | Authorises a specific IPv4 address or CIDR range | ip4:203.0.113.5 or ip4:203.0.113.0/24 |
ip6: | Authorises a specific IPv6 address or CIDR range | ip6:2001:db8::/32 |
a | Authorises the IP addresses in the domain's A record | a or a:mail.example.com |
mx | Authorises the IP addresses of the domain's MX records | mx |
redirect= | Replaces the entire SPF evaluation with another domain's record | redirect=_spf.example.com |
exists: | Advanced macro-based mechanism for dynamic lookups | exists:%{i}._spf.example.com |
Qualifiers
The qualifier before all determines what happens to mail that doesn't match any mechanism:
| Qualifier | Meaning | Result |
|---|---|---|
-all | Hard fail — reject the message | Fail |
~all | Soft fail — accept but mark as suspicious | SoftFail |
?all | Neutral — no opinion | Neutral |
+all | Pass everything — never use this | Pass |
A real-world example
A company using Microsoft 365, SendGrid for transactional email, and a legacy on-premises relay might have:
v=spf1 include:spf.protection.outlook.com include:sendgrid.net ip4:198.51.100.25 -allThis says: Microsoft 365 servers can send for us, SendGrid servers can send for us, our on-prem server at 198.51.100.25 can send for us, and everything else should be rejected.
The DNS lookup limit
SPF has a hard limit of 10 DNS lookups per evaluation. This is defined in RFC 7208 and is enforced by receiving mail servers. When the limit is exceeded, SPF returns a PermError result, which most receivers treat as a failure. This means all mail fails SPF — not just the mail that would have been checked by the 11th lookup.
What counts as a lookup
Each of these mechanisms triggers one or more DNS lookups:
| Mechanism | Lookups consumed |
|---|---|
include: | 1 (plus any lookups in the included record) |
a or a:domain | 1 |
mx or mx:domain | 1 (plus 1 per MX record resolved) |
redirect= | 1 |
exists: | 1 |
These mechanisms do not consume lookups:
| Mechanism | Lookups consumed |
|---|---|
ip4: | 0 |
ip6: | 0 |
all | 0 |
How includes chain
The dangerous thing about include: is that it's recursive. When you write include:spf.protection.outlook.com, the receiver resolves that domain's SPF record, which itself may contain further includes. Each one counts against your limit of 10.
For example, Microsoft 365's SPF chain currently looks like this:
include:spf.protection.outlook.com → 1 lookup
include:spf-a.outlook.com → 1 lookup
include:spf-b.outlook.com → 1 lookupThat's 3 lookups consumed just for Microsoft 365. Add Google Workspace (2-3 lookups), SendGrid (1 lookup), and a few more services, and you're already at 8-9 lookups before you add anything else.
Checking your lookup count
You can check your current lookup count with online tools like MXToolbox's SPF Record Lookup, or by counting manually. Sentura also tracks your lookup count and warns you when you're approaching the limit.
What is SPF flattening?
SPF flattening is the process of resolving all include: mechanisms down to their final IP addresses and replacing the includes with ip4: and ip6: entries. Since IP mechanisms don't consume DNS lookups, this can dramatically reduce your lookup count.
Before flattening
v=spf1 include:spf.protection.outlook.com include:_spf.google.com include:sendgrid.net include:servers.mcsv.net ~allThis uses 8-10 lookups due to chained includes.
After flattening
v=spf1 ip4:40.92.0.0/15 ip4:40.107.0.0/16 ip4:52.100.0.0/15 ip4:104.47.0.0/17 ip4:147.243.0.0/16 ... ~allThis uses 0 lookups.
When you need flattening
- You're at or near the 10-lookup limit
- You use 4 or more third-party email services
- You're getting
PermErrorresults in DMARC reports
The trade-off
Flattened records need maintenance. When a provider changes their IP ranges (which Microsoft and Google do regularly), your flattened record becomes stale and legitimate mail may fail SPF. Automated flattening services — including Sentura — monitor for these changes and update the record for you.
Common SPF mistakes
1. Too permissive — including providers you don't use
Every include: you add authorises that provider's entire IP range to send as your domain. If you once trialled Google Workspace but now only use Microsoft 365, remove include:_spf.google.com. Unused includes waste lookups and expand your attack surface.
2. Missing senders
This is the most common cause of SPF failures in DMARC reports. Organisations frequently forget about:
- Transactional email services — password resets, order confirmations, invoices sent through SendGrid, Postmark, or Amazon SES
- CRM platforms — HubSpot, Salesforce, or Dynamics 365 sending marketing email or notifications
- Helpdesk tools — Zendesk, Freshdesk, or ServiceNow sending ticket updates
- Payroll and HR systems — BambooHR, Gusto, or similar sending payslips and notifications
- Legacy on-premises relays — SMTP relays, printers, or line-of-business applications that send email via a static IP
Before moving to DMARC enforcement, audit your DMARC aggregate reports to find every service sending as your domain.
3. Exceeding the 10-lookup limit
This is the most damaging mistake. When you exceed 10 lookups, SPF returns PermError and all mail fails SPF — not just the mail checked by the extra lookups. The fix is either to remove unnecessary includes or to flatten your record.
4. Publishing duplicate SPF records
The SPF specification requires exactly one TXT record starting with v=spf1 per domain. If you publish two (which often happens when a new service's setup guide says "add this TXT record" and someone adds it alongside the existing one), SPF returns PermError for every message.
# Wrong — two SPF records
v=spf1 include:spf.protection.outlook.com ~all
v=spf1 include:sendgrid.net ~all
# Correct — one combined record
v=spf1 include:spf.protection.outlook.com include:sendgrid.net ~all5. Using +all
The +all qualifier means "pass everything, regardless of whether it matches a mechanism." This completely defeats the purpose of SPF. Any server in the world passes your SPF check. Always use -all (hard fail) or ~all (soft fail).
6. Using ?all when you mean ~all
The ?all qualifier means "neutral — I have no opinion." This is almost as bad as +all because it provides no signal to receivers. Use ~all during rollout and -all once you're confident in your record.
Common provider SPF includes
The table below lists the SPF include values for major email-sending platforms. Always check the provider's current documentation, as these can change.
| Provider | SPF include | Typical lookups consumed |
|---|---|---|
| Microsoft 365 | include:spf.protection.outlook.com | 2-3 |
| Google Workspace | include:_spf.google.com | 3-4 |
| SendGrid | include:sendgrid.net | 1 |
| Mailchimp (Mandrill) | include:servers.mcsv.net | 1 |
| HubSpot | include:_spf.hubspot.com | 1 |
| Zendesk | include:mail.zendesk.com | 1 |
| Proofpoint | include:spf.proofpoint.com | 1-2 |
| Amazon SES | include:amazonses.com | 1 |
| Mailgun | include:mailgun.org | 1 |
| Salesforce | include:_spf.salesforce.com | 1-2 |
Count before you add
Before adding a new include, check how many lookups you're already using. If you're at 8 or 9, that new service might push you over the limit and break SPF for all your mail.
SPF and DMARC alignment
SPF on its own only checks the envelope sender (the MAIL FROM address used in the SMTP transaction). It does not check the From: header that the recipient sees in their email client. This means an attacker can spoof the visible From: address while using a different envelope sender that passes SPF.
DMARC closes this gap by requiring alignment — the domain authenticated by SPF must match (or be a subdomain of) the domain in the From: header. Without alignment, SPF pass alone is not enough for DMARC to pass.
This is why configuring SPF correctly is a necessary step toward DMARC enforcement, but it's not sufficient on its own. You also need DKIM, and you need DMARC to tie them together.
Recommended next steps
- Audit your current SPF record — check lookup count, verify all includes are still needed
- Review DMARC reports — identify any senders not covered by your SPF record
- Flatten if needed — if you're near the 10-lookup limit, consider automated flattening
- Move toward -all — once you're confident in your record, switch from
~allto-all
Further reading
- What is SPF? — a shorter introduction
- What is DMARC?
- What is DKIM?
- DMARC Enforcement Guide
- Multi-Domain DMARC Reporting