Somebody in marketing signs up for a new newsletter platform. Support adds a helpdesk that sends from your domain. Finance switches invoicing tools. Each time, the vendor's setup guide says the same thing: "add include:vendor.example to your SPF record." Each time, someone does.
Then one day mail starts landing in spam — not from the new vendor, but from everything. Your main mail platform, your password resets, your invoices. Nothing changed in those systems. What changed is that your SPF record crossed a limit that has existed since 2014, and every receiver now treats it as broken.
The rule
SPF is evaluated by the receiving server, which has to resolve your record in real time while a message is waiting. To stop a single lookup turning into a denial-of-service amplifier, RFC 7208 sets a hard ceiling: evaluating an SPF record may trigger no more than ten DNS-querying mechanisms.
These mechanisms count towards the limit:
| Counts | Does not count |
|---|---|
include: | ip4: |
a and a: | ip6: |
mx and mx: | all |
ptr (deprecated — remove it) | v=spf1 |
exists: | Tags such as exp= |
redirect= |
The crucial part is that the count is recursive. Every include: costs one lookup, and then everything inside that vendor's record costs more. A vendor whose record contains three nested includes costs you four, not one.
How the arithmetic goes wrong
A record like this looks modest. It has five includes, so it feels like five lookups:
v=spf1 include:_spf.google.com include:sendgrid.net include:servers.mcsv.net
include:mail.zendesk.com include:_spf.salesforce.com ~all
In practice each of those expands. A typical major provider's record contains several nested includes of its own, and one or two vendors adding a mechanism on their side — entirely outside your control — is enough to push the total past ten. You changed nothing; your SPF still broke.
What "PermError" actually does to you
When evaluation exceeds the limit, the receiver does not return "fail". It returns PermError: a permanent error meaning the record could not be evaluated. In practice most receivers treat PermError the same way they treat a domain with no SPF record at all.
That has a knock-on effect. SPF can no longer contribute a pass to DMARC, so the only way a message can satisfy DMARC is an aligned DKIM signature. If DKIM is missing, signed by a vendor's own domain, or broken by a mailing list that modified the message, DMARC fails — and your policy is applied to your own legitimate mail.
What breaks without it
- Everything degrades at once. The limit is a property of the record, not of one vendor, so the moment it is exceeded every system sending from your domain loses its SPF pass simultaneously.
- Your dashboards stay green. Vendors report a successful send. The message left their servers; what happened at the receiver is not shown. There is no bounce to investigate.
- Enforcement turns it into an outage. With
p=rejectand no aligned DKIM, mail that would otherwise have been filed as spam is now refused outright. - It regresses on its own. Because the count includes vendor records, you can pass today and fail next month with no change on your side.
all. A record with no all mechanism is treated as neutral — it authorises nobody and protects nothing. The limit problem stays exactly where it was.How to check it in 30 seconds
Run an SPF Lookup for your domain. It expands every include: and redirect= recursively, shows the full tree, and gives you the running total against the limit of ten — so you can see which vendor is responsible rather than guessing.
Before you publish a change, paste the new record into the SPF Record Validator. It counts the lookups of a record that does not exist in DNS yet, which is the only safe way to test an edit to a live domain.
Fix it
- Remove what you no longer use. Old newsletter tools, a former helpdesk, a migrated mail platform. Dead includes are the most common cause and the safest thing to delete.
- Remove
ptrentirely. It is deprecated by RFC 7208, slow, and costs a lookup. - Drop redundant mechanisms. If your mail servers are already covered by a vendor's
include:, the extraaandmxare two lookups you are paying for twice. - Move bulk mail to a subdomain. Send marketing from
news.example.comwith its own SPF record and its own ten-lookup budget. This is the structural fix: your transactional mail stops competing with campaign tooling for space. - Flatten only as a last resort. Replacing an
include:with the vendor's literalip4:ranges removes lookups, but freezes a list that the vendor may change without telling you. If you flatten, re-check the source record on a schedule. - Publish exactly one SPF record. Two
v=spf1records on the same name is a permanent error regardless of the lookup count.
Once the count is back under ten, make sure DKIM is signing with your own domain so that SPF is not the only thing standing between you and a DMARC failure. That relationship is covered in how a receiver actually decides.
Then keep it that way
An SPF record is one of the few pieces of your infrastructure that can break without anyone touching it, because part of it is maintained by other companies. A quarterly manual check will not catch a vendor that adds an include the week after you looked.
StatusDNS re-checks your SPF record on a schedule, expands it in full, counts the lookups the way a receiver does, and alerts you by email, Slack or webhook when the record changes or the count crosses the limit. If you are about to move to an enforcing DMARC policy, read the staged rollout plan first.