Summarise SPF
Replace includes with their IP ranges and get back under the 10-lookup limit.
This tool needs a free account. Everything else on mailtools stays usable without signing in.
An SPF record may trigger at most ten DNS lookups when it is evaluated (RFC 7208
section 4.6.4). Every include: costs one of them, and it brings its provider's
own lookups along: behind _spf.google.com sit about four more in practice. Three
or four service providers are therefore enough to break the limit. What happens then is the
unpleasant part: the record is not partially evaluated, it counts as faulty as a whole
(PermError). SPF fails for all of your senders, not just for the last entry.
This procedure is usually called SPF flattening. The tool is named Summarise SPF here because that describes what happens: several entries become one. The thing itself is the same.
What this tool does
It resolves the includes in your record and replaces them with the IP ranges behind them.
include:_spf.google.com becomes Google's ip4: and ip6:
entries. If everything then fits into one entry, your record costs no lookup
at all when evaluated, because there is nothing left to look up. If it grows too large, the
tool spreads it across several entries held together by the first one via
include:; one lookup per additional entry remains, and the sum still works out
because your providers' lookups are gone.
Two things stay in place. a and mx point at your own
infrastructure and are not frozen, otherwise they would be silently wrong after your next
server move. And providers that publish no list at all but authorise every sender
individually through a DNS query (exists:, as Salesforce does) keep their
include: -- there is nothing to freeze there, today or ever. The tool tells you
when that happened.
If all of it together yields no gain, you get no record. An output that costs as many lookups as before and additionally carries the expiry date of a snapshot would not be an improvement but a bad trade.
Your original record stays in place and editable. That is not a side note, it is the reason
this function requires an account: a summarised record no longer shows which range belongs to
which provider. If you later drop a service, you would have to work out which of a hundred
networks were its. With the saved original it is one line: delete the include:,
summarise again, done.
Reading the result
Above the result you see how many lookups the old record cost and how many the new one costs. Below are the entries you need to create, each with its full name. In a chain the first entry belongs on your domain itself and the others on the names given; only all of them together make up the record. Every entry stays below 450 octets so the DNS answer fits into a UDP packet (RFC 7208 section 3.4).
If you get no result, that is deliberate. This tool would rather produce no record at all
than an incomplete one: a record that silently forgets a provider looks finished and rejects
that provider's mail, and you would only notice it through answers that never arrive. It
therefore refuses when an include does not resolve, when the record contains
exists:, ptr or redirect= (those cannot be translated
into IP ranges), when even the chain would breach the ten lookups again, or when nothing
would be saved in the end.
Background: what this optimisation costs
A summarised record is a snapshot of someone else's infrastructure. As
long as include:_spf.google.com sits in the record, every evaluating server
fetches Google's current ranges. Once the ranges are written out, today's state applies, and
it keeps applying until you renew it. If the provider brings new address ranges into service,
your record rejects their mail without any error showing up: the record is syntactically
fine, the check runs through cleanly, only the outcome is wrong.
That is why this function is tied to an account, why every result carries its age visibly, and why the way back is always open: your original stays saved. Given the choice, first see whether includes can be dropped altogether: an old newsletter service, a retired ticket system, a provider that has long since signed with DKIM. Only when that is exhausted is summarising the right step.
Common problems
- The record was summarised and nobody ever renewed it. The most dangerous state there is, because it is silent. Check it regularly against the saved original.
- Only the first entry of the chain was created. The evaluating server then
does not find the other names, the includes run into nothing, and in the end your
allrule applies to practically every message. - The old record was left standing next to it. Two SPF records on the same domain are a PermError (RFC 7208 section 4.5), and then neither of them applies.
- The chain was trimmed by hand. Removing individual ranges without knowing which provider they belong to locks out your own senders. Change the original instead and summarise again.
Common questions
- Is this the same as SPF flattening?
- Yes. <em>SPF flattening</em> is the common name for exactly this procedure: includes are replaced by the IP ranges behind them. It is called summarising here because that describes the step rather than the result. The name changes nothing about the trade-off: a summarised record is a snapshot of somebody else's infrastructure and needs renewing.
- Why do I need an account for this?
- Because the result becomes worthless without your original record. A summarised record does not show which IP range belongs to which provider. If you later want to remove a service, you would have to work out which of a hundred networks were its. With the saved original you delete one line and summarise again. On top of that, a summarised record ages and therefore needs monitoring, and both of those require that we know the original.
- How often do I have to renew the record?
- There is no fixed interval, because it depends on your providers. Large providers change their ranges rarely, but they do change them. As a rule of thumb: immediately after any change to your sending setup, otherwise every few months. When you summarise again, the tool shows you which ranges are new and which have gone, so you do not have to guess.
- What happens when a provider brings new IP ranges into service?
- Your record rejects their mail as if it came from a stranger. That is the price of this optimisation and the reason it is not the right choice for everyone. No error shows up anywhere: the record is syntactically fine, the check runs through cleanly, only the outcome is no longer correct. If you do not want to keep an eye on that, you are better off with fewer includes than with frozen ranges.
- Why do I get several entries instead of one?
- Because it all does not fit into one record. RFC 7208 section 3.4 recommends that the name and the record text together stay below 450 octets so the DNS answer fits into a UDP packet. Above that the resolver must fall back to TCP, and where that fails the record counts as absent. The chain works around it: the first entry sits on your domain and points to the others. It is cut per provider so that a change at one of them does not shift every entry.
- Does the chain not cost lookups again?
- Yes, one per chain member. That is the trade: instead of your providers' lookups, which you do not control and which can be deeply nested, you pay a fixed, manageable number for your own entries. If even that would breach the ten lookups, the tool produces nothing at all rather than handing you a solution that keeps the problem.
- Why are a and mx not resolved as well?
- Because they point at your own infrastructure. Frozen, they would be silently wrong after your next server move, and that for exactly the addresses you control yourself and therefore watch least. They cost one lookup each, which is easy to keep, and they move into the new record unchanged.
- My record contains exists: or ptr, why does it not work?
- Those mechanisms make a statement about the querying address, not about a fixed set of senders. There is no list of IP ranges that means the same thing. Simply leaving them out would produce a record that allows less than your original, and you would only notice through rejected mail. So the tool refuses here instead of building something that roughly fits.
- Does summarising change my policy?
- No. The qualifier of your all mechanism is left alone: ~all does not quietly become -all. The chain members do end in -all, but that is a different matter: they are only entered via include:, where all that counts is whether a mechanism matches. The decision about non-matching mail is made in the first entry, which is where your own setting sits.