SPF
SPF (Sender Policy Framework) is a DNS record that lists the servers allowed to send email from your domain. Without it, anyone can send mail claiming to be from you. With it, receivers check the list and reject forgeries. Specified in RFC 7208.
How receivers validate
A mail server receives a message from you@yourdomain.com. It checks the sending IP against your list. If the closing rule is strict and the IP is not on the list, the message is rejected before delivery.
- 01·receiving MTAstepMAIL FROM: you@yourdomain.com arrives from 198.51.100.5
- 02·receiver queries DNSstepTXT? yourdomain.comresultv=spf1 include:_spf.google.com ip4:203.0.113.10 -all
- 03·expand mechanismsstepresolve include:_spf.google.com (and chains)result198.51.100.5 not in any allowlist
- 04·apply closing rulestep-all = strict failresultreject at SMTP handshake
Anatomy of a record
A typical SPF record has three parts: the version, the mechanisms that name authorised senders, and a closing rule.
always the opening. Only one SPF record per domain.
a literal IP you control. Cheapest mechanism: no DNS lookup cost.
delegates to a provider's SPF fragment. Counts against the 10-lookup ceiling, recursively.
closing rule. -all = strict fail, ~all = softfail, ?all = neutral, +all = allow everything (disaster).
The closing mechanism
This tag decides whether your SPF protects you:
| Token | Meaning | Forged mail outcome |
|---|---|---|
-all | Strict fail | Rejected at the SMTP handshake |
~all | Soft fail | Routed to spam or quarantined |
?all | Neutral | Delivered. Result logged only. |
+all | Allow everything | Delivered. SPF is functionally absent. |
Sudory marks -all as pass. Everything else is a warn. No record at all is a fail.
The 10-lookup ceiling
SPF caps DNS lookups at 10 per evaluation. RFC 7208 §4.6.4 counts these: include, a, mx, ptr, exists, and redirect. Includes recurse: a provider's SPF may include others, and those count too.
Past 10 lookups, the record returns permerror and receivers treat it as a fail. A separate limit of two void lookups (NXDOMAIN or empty answer) triggers permerror the same way.
If you are near the ceiling: consolidate with a flattening service, drop senders that are no longer sending, or switch to ip4: literals for providers with stable IP ranges.
Building your record
1. Collect the includes
Every service that sends your mail publishes an SPF fragment. The provider name links to each setup guide.
| Provider | Include string |
|---|---|
| Google Workspace | include:_spf.google.com |
| Microsoft 365 | include:spf.protection.outlook.com |
| SendGrid | include:sendgrid.net |
| Postmark | include:spf.mtasv.net |
| Mailgun | include:mailgun.org |
Watch the lookup math. include:mailgun.org costs three (nested includes). include:spf.protection.outlook.com costs two. Two transactional vendors plus Workspace put you past six before you add your own ip4: literals.
2. Compose one record, end with -all
v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.10 -allOne line, one TXT record. If you already have one, merge. Two records starting with v=spf1 is a permerror.
3. Publish at the root
| Field | Value |
|---|---|
| Type | TXT |
| Host | @ (or yourdomain.com) |
| Value | v=spf1 include:... -all |
| TTL | 3600 |
Common mistakes
- Ending with
+all. Authorises every server on the internet. Almost always a copy-paste mistake. - Two SPF records. Both start with
v=spf1. Receivers returnpermerror(RFC 7208 §3.2). Merge into one. - Forgetting subdomains. SPF does not inherit. Each sending subdomain needs its own record.
- Staying on
~allforever. "We will tighten later" rarely happens. Only-allrejects forgeries.
Check your SPF record: scan your domain. Sudory resolves your TXT records, follows redirect= up to three levels, and returns the pass, warn, or fail verdict.
