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 all is unreachable, because all matches everything.
  • A record with no match and no final all returns neutral, 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, exists and redirect — including every one encountered inside an included record.

What does not count:

  • ip4, ip6 and all, 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.