permerror means the receiver could not evaluate your SPF record as published, and trying again will give the same answer. Too many DNS lookups is the most common reason. The others are two SPF records on one domain, a syntax error, and more than two lookups that return nothing. DMARC treats every one of them as SPF not passing.
How the ten are counted
RFC 7208, section 4.6.4 caps an evaluation at ten terms that cost a DNS query: include, a, mx, ptr, exists and the redirect modifier. ip4, ip6 and all cost nothing.
The count runs across the whole tree. include:_spf.example-provider.com costs one, and every include inside that provider's record costs one more. A record with five includes can easily need fifteen lookups, and reading your own record shows only the first five of them.
There is also a limit on void lookups, queries that return no records or a name that does not exist. The RFC recommends allowing two, and at receivers that apply that limit the third is a permerror. Includes for services that no longer exist are the usual source.
Why it fails for some mail and not for other mail
Evaluation stops at the first mechanism that matches. A server listed early in the record passes after three lookups; a server listed at the end needs the whole tree and goes over. So the same record lets the main mailbox through and fails the CRM, and testing from the mailbox says everything is fine. The SPF checker counts every term, not only the terms a single evaluation reached, for that reason.
Bringing the count down
In order of how safe they are:
- Remove includes for services you no longer use. They cost lookups and authorise servers you do not control.
- Replace
aandmxwith addresses when your own servers send.ip4:203.0.113.5costs nothing, whilemxtakes one of the ten (the address lookups for its MX hosts run against a separate cap of their own). - Drop
ptr. The RFC says not to use it, and it is slow. - Move a sender to a subdomain. A newsletter on
news.example.comwith its own SPF record and its own return path takes its includes out of the main record. DMARC still passes with relaxed alignment. - Flatten an include into addresses as the last resort. It brings the count down at once, and then the provider changes its ranges and your copy is out of date. If you flatten, re-check it on a schedule.
Do not split one record into two to get two sets of ten. Two SPF records on one name are a permerror of their own; see multiple SPF records.
How the test reports it
Two numbers sit side by side in the report: the lookups the receiving server spent on the test message, and the lookups the whole record costs with every branch followed. When the message passes but the record is over ten, the report says so and names the include chain that goes over, which is the one to shorten first. The rest of the SPF check is described in the documentation.