Know your SPF lookup budget before receivers do
Your record is expanded include by include and counted against the ten lookup limit. When a vendor quietly adds one more include and pushes you over, you find out from us, not from a PermError in somebody else's log

The lookup budget
Every include and redirect is followed and counted, so you can see how much of the ten you have spent and on what
- Include and redirect expansion
- Void lookups counted separately
- Syntax errors named, not just flagged
- A warning in the panel from the ninth lookup

A flattened record when it is safe
Where the chain resolves cleanly, you get a record you can paste, split across _spf1 and _spf2 if it does not fit in one string
- Ready record, not advice
- Withheld when the chain is incomplete
- Overflow chained into _spfN
- Your all qualifier preserved

When somebody changes it
The published record is compared with its previous value on every run, and you get the old and new side by side
- Before and after, not just a flag
- Loose all found inside includes
- Macros flagged where they hide cost
- Multiple SPF records detected

What the SPF check actually does
Every item here is something the checker performs on your record. Where a limit applies, the limit is named
Include and redirect expansion
Follow the chain, not just the first line
Each include and redirect is resolved and the tree is shown with the record found at every node. Public lookups expand two levels, an account expands up to five
The ten lookup limit, counted
And the void limit nobody remembers
DNS-consuming mechanisms are counted the way RFC 7208 counts them. Void lookups have their own limit of two under section 4.6.4, and exceeding that is a PermError just the same
A loose all hiding in an include
Where your policy leaks
A vendor whose record ends in +all or ?all quietly widens your authorization. Every node in the tree is checked for it and reported with the full path to the include that carries it
Syntax that fails at the receiver
Named, with the term that broke
Two SPF records on one name, an unknown mechanism, a malformed IPv4 or IPv6 range, an underscore where a hostname belongs. Each one is reported against the term it appears in
A flattened record, or none at all
Never a half-resolved one
Where the whole chain resolves without a timeout, a macro or a ptr, you get a record ready to publish, split into _spf1 and _spf2 when it will not fit. Where it does not resolve cleanly, nothing is offered, because a partial flatten drops senders
The record as it was yesterday
Old and new, side by side
The published record is hashed on every run and compared with the previous value. A change gives you both versions and the time, and an email if it moved the check into a failing state
What spends the budget, and what is free
Ten lookups is the whole allowance, and half the mechanisms people worry about do not touch it while one they never think about can end the record early
| In your record | Costs a lookup | Why |
|---|---|---|
| include, redirect | Yes, and everything inside it too | The other record is fetched and its own mechanisms are counted against your allowance, not theirs |
| a, mx | Yes, one each | Each one resolves a name at send time, and mx resolves the hosts it finds as well |
| exists, ptr | Yes, one each | ptr is discouraged by RFC 7208 for exactly this reason and receivers may ignore it |
| ip4, ip6 | No | The address is already in the record, so nothing has to be asked |
| all | No | It is the verdict at the end, not a question |
Two of the 10 may come back empty. Past 2 void answers the record is a permerror, which receivers treat as no SPF at all
Three steps, about ten minutes
Nothing to install and nothing to change in your mail flow. The check reads public DNS
Enter the domain
The record is fetched and the chain expanded. You see the tree, the lookup count against ten, and any syntax error with the term that caused it
Read where the budget goes
Each include shows the record it published at that moment, so you can tell which vendor is expensive and which one you no longer use
Leave it watching
Add the domain to an account and the same check runs every ten minutes. You get an email when the record changes or when the check starts failing
Questions about SPF
The lookup limit, what flattening does and does not solve, and what happens when a vendor changes their record
A PermError occurs when SPF evaluation cannot complete, most commonly because the 10-lookup limit is exceeded or the record is syntactically malformed. When this happens, SPF authentication fails and mail is often rejected or marked as spam.
Each include and redirect mechanism triggers additional DNS queries. Nested includes compound these queries quickly, so a record that appears short can easily exceed the 10-lookup limit once fully expanded across third-party vendor chains. RUA•Watcher solves this complexity by providing full visibility into the evaluation path.
A void lookup is a DNS query that returns no usable result like NXDOMAIN. RFC 7208 imposes strict limits on void lookups, typically allowing only two. Exceeding this limit triggers a PermError, making it critical to prune dead records and inactive vendors.
Flattening replaces DNS-based mechanisms with their resolved IP addresses and ranges. This drastically reduces lookup usage but requires automated management, as vendor IP ranges change frequently. Flattening is recommended when your legitimate sender list naturally exceeds 10 lookups.
SPF infrastructure is dynamic. Third-party vendors can update their own include records at any time, which might push your domain over the lookup limit or introduce syntax errors without your knowledge. Monitoring ensures you catch these shifts before they impact deliverability.
Specifications this page relies on
- RFC 7208Sender Policy Framework (SPF), Version 1
Count your lookups before a receiver does
Your lookup count, your include tree and any loose all inside it, in about ten minutes. The first domain costs nothing and needs no card