SPF mechanisms and modifiers
Every SPF mechanism and modifier, what it matches, and whether it costs one of your ten DNS lookups — plus the limits that break real records.
An SPF record is a single DNS TXT record made of mechanisms, each optionally carrying a qualifier, plus a small number of modifiers. This page is the complete list, with what each one costs against SPF's DNS lookup budget — the limit that breaks most real records.
If you want to check a specific domain rather than read the reference, use the SPF checker.
How evaluation works
A receiving server takes the connecting IP address and the envelope sender's domain, fetches that domain's SPF record, and walks the mechanisms left to right. The first one that matches decides the result, and evaluation stops there.
Two consequences follow, and both cause real bugs:
- Order matters. Anything after a matching
allis unreachable, becauseallmatches everything. - A record with no match and no final
allreturnsneutral, which is treated much like having no policy at all.
Qualifiers
Every mechanism may be prefixed with a qualifier. Omitting it means +.
| Qualifier | Result | Meaning |
|---|---|---|
+ |
pass | The IP is authorised. This is the default. |
- |
fail | The IP is not authorised, stated definitively. |
~ |
softfail | Not authorised, but do not reject on this alone. |
? |
neutral | No assertion either way. |
In practice only the qualifier on the final all gets much attention, because that is the one deciding what happens to everything unmatched.
Mechanisms
The lookup column is what matters for staying under the limit described below.
| Mechanism | Matches when | Costs a lookup |
|---|---|---|
all |
Always. Put it last. | No |
ip4: |
The IP falls in the given IPv4 address or CIDR range. | No |
ip6: |
The IP falls in the given IPv6 address or CIDR range. | No |
a |
The IP matches an A or AAAA record of the domain (or of an explicit domain given after a colon). | Yes |
mx |
The IP matches an A or AAAA record of any of the domain's MX hosts. | Yes |
include: |
The named domain's SPF record produces a pass. | Yes |
exists: |
The named domain resolves to any A record. Used for macro-based tricks; rare. | Yes |
ptr |
Reverse DNS for the IP resolves to a name in the domain. Deprecated. | Yes |
ip4 and ip6
The only mechanisms that cost nothing. If you know a sender's addresses and they are stable, listing them literally is the cheapest way to authorise them. The trade is maintenance: when the sender renumbers, your record is silently wrong.
a and mx
Both resolve the domain's own records. mx is a common misunderstanding — it authorises the servers that receive your mail, which are frequently not the ones that send it. Adding it reflexively costs a lookup and often authorises nothing useful.
include
The workhorse, and the source of nearly every lookup problem. include: counts as one lookup plus every lookup inside the included record, recursively, all charged to your budget rather than the vendor's. A single vendor include can quietly consume four or five.
include also does not mean "insert here". It means "evaluate that record and, if it passes, we pass". A -all inside an included record does not cause your evaluation to fail — it just fails to match, and evaluation continues with your next mechanism.
ptr
Deprecated by RFC 7208 and ignored by some receivers. It is slow, it depends on reverse DNS you may not control, and it costs a lookup. Replace it with explicit ip4 or ip6 ranges.
exists
Matches if the given name resolves to any A record. Almost always used with macros to build a name from the connecting IP or sender, for per-user or per-IP policies. Powerful, rarely needed, and worth avoiding unless you know exactly why you want it.
Modifiers
Modifiers appear at most once each and are not positional in the same way mechanisms are.
| Modifier | Effect | Costs a lookup |
|---|---|---|
redirect= |
Replace this record's evaluation entirely with another domain's. | Yes |
exp= |
Names a TXT record holding an explanation string for failures. | No (only on failure) |
redirect is for domains that should share one central policy — useful across a portfolio of domains that all send identically. Two things to know: it is ignored if the record also contains an all mechanism, and unlike include, a failure in the redirected record is your result.
The lookup budget
The limit is 10 DNS-querying mechanisms per evaluation. Exceeding it produces permerror, which most receivers treat as a failure. This is the single most common way a well-intentioned SPF record stops working.
What counts:
- Each
include,a,mx,ptr,existsandredirect— including every one encountered inside an included record.
What does not count:
ip4,ip6andall, however many you list.- The initial lookup of your own SPF record.
There is a second, less known limit: no more than 2 "void" lookups — queries that return no records — before evaluation fails. Includes pointing at domains that no longer publish SPF will trip this even when the total count is under 10.
| Limit | Value | On breach |
|---|---|---|
| DNS-querying mechanisms | 10 | permerror |
| Void lookups | 2 | permerror |
mx records resolved per mx mechanism |
10 | permerror |
| Record length per TXT string | 255 characters | Must be split into multiple strings |
Result codes
| Result | Meaning | Typical handling |
|---|---|---|
pass |
The IP is authorised. | Accept, subject to other signals. |
fail |
Matched a - qualifier. |
Reject or bin, depending on DMARC policy. |
softfail |
Matched a ~ qualifier. |
Accept and mark suspicious. |
neutral |
Matched ?, or nothing matched and there is no final all. |
Treated like no policy. |
none |
No SPF record exists, or the domain does not exist. | Treated like no policy. |
permerror |
The record is broken: over the lookup limit, duplicated, or unparseable. | Usually a failure. |
temperror |
A transient DNS failure. | Retried later. |
The two to watch are permerror and neutral. Both mean your SPF is doing nothing, and neither is visible unless you look.
Things worth knowing
One record per domain. Two records starting v=spf1 is a permerror, not a merge. Receivers do not pick the more permissive one — the whole evaluation fails.
SPF authorises the envelope sender, not the visible From address. A message can pass SPF while displaying a forged From: header. Closing that gap is what DMARC alignment does.
SPF breaks on forwarding. The forwarding server is not in your record and never will be. DKIM signatures survive forwarding, which is why DMARC accepts either mechanism.
Subdomains do not inherit. An SPF record on example.com says nothing about mail.example.com. Each sending subdomain needs its own. DMARC is the opposite — it does apply down the tree — and that asymmetry catches people out.
Related
- SPF checker — parse a live record and count its lookups.
- DMARC checker — the policy that gives an SPF result consequences.
- DKIM checker — the signature-based half of authentication.
- Full domain check — SPF, DKIM, DMARC and MX together.