SPF lookup counter
RFC 7208 caps an SPF evaluation at ten DNS lookups. Over the cap it is a permerror, and most receivers treat a permerror as no SPF at all. This walks the whole include tree and shows you exactly where the count goes.
What counts against the ten
| Mechanism | Cost | Notes |
|---|---|---|
include: | 1 + its own | Recursive. An include that itself has four includes costs you five. |
redirect= | 1 + its own | Same as include, and it replaces the rest of the record. |
a a: | 1 | Including the CIDR forms, a/24 and a:host/24. |
mx mx: | 1 | And capped separately at ten address records per evaluation. |
exists: | 1 | Often carries a macro, so the cost can depend on the sending IP. |
ptr | 1 | Deprecated by RFC 7208. Some receivers ignore it. Remove it. |
ip4: ip6: | 0 | No DNS query, so unlimited. |
all exp= | 0 | exp= is only fetched on a fail, and never counts. |
Every mechanism can carry a qualifier, so +include:, -a and
~mx cost exactly what the unqualified form costs. Tools that match on the bare
token miss them and report a broken record as healthy.
Why this is worth checking
It is the failure nobody sees coming. The record resolves. It reads correctly. It passes a visual inspection. It has simply stopped authenticating, usually because somebody added one more vendor to a record that was already at nine. Across 100,000 domains, 3.4% of every published SPF record had already crossed the line.
On flattening
Flattening means replacing an include: with the IP ranges it currently
resolves to. It fixes the count today and creates a slower problem: when the provider adds a
sending range, your record does not know, and mail from the new range fails SPF with no error
anywhere to tell you. If you flatten, you own a record that has to be re-generated on a
schedule, and somebody has to still be doing that in a year.
Cheaper answers first: remove vendors that no longer send, move mail to a subdomain with its own record, and collapse two ESPs into one.