SPF PermError: the four causes and how to fix them

“SPF PermError” means your domain's SPF record can't be evaluated, and the recipient treats it as invalid. One of four mistakes is usually behind it, and all of them can be fixed in a few minutes. Here is how to find the right one.

What a PermError is

For every email, the recipient looks up the sender domain's SPF record and checks whether the sending server is allowed. If the record is faulty, the result is PermError (“permanent error”). It doesn't mean “rejected”, but SPF counts as not passed. With a strict DMARC policy, that quickly leads to rejected mail or the spam folder, and large providers such as Gmail and Yahoo expect SPF or DKIM with alignment.

Cause 1: more than 10 DNS lookups

SPF allows at most 10 lookups that trigger further DNS queries. These include include, a, mx, exists, redirect and ptr. ip4, ip6 and all are not counted. Each include counts together with all the lookups contained in the included record itself.

This is typical with many connected services: newsletter tool, mail system, CRM, ticketing, accounting. Each one brings an include with several lookups.

How to fix it:

Cause 2: two SPF records

A domain may have exactly one TXT record that starts with v=spf1. Two records result in a PermError, even if each is correct by itself. This often happens when a new service is set up and its instructions say to “create an SPF record”.

Fix: merge both into one. From

v=spf1 include:_spf.google.com ~all
v=spf1 include:mailer.example.net ~all

you get

v=spf1 include:_spf.google.com include:mailer.example.net ~all

The SPF generator puts this together in one step.

Cause 3: syntax errors

Cause 4: records that don't exist

If an include points to a domain without an SPF record, that's an error. In addition, SPF allows at most two “void” lookups that return no result at all. More than two also lead to a PermError. This affects records with old, discontinued services.

Fix: check each include to see whether the target still exists, and remove dead entries.

Finding and testing the error

  1. Look up the record with the SPF checker. It shows all included records as a tree, counts the lookups and marks syntax errors.
  2. Fix the error in DNS and wait for the TTL, usually minutes to hours.
  3. Check again, then send a test email to see the result from the recipient's point of view: the test on the home page shows SPF, DKIM and DMARC together.

Frequently asked questions

What is the difference between PermError and TempError?

A TempError is a temporary problem, for example a DNS server that doesn't answer. A PermError lies in the record itself and only goes away when you correct it.

Is ~all or -all better?

Both are valid. -all is stricter (“reject everything else”), ~all only marks as suspicious. With a DMARC policy, ~all is usually enough because DMARC makes the decision.

My record has only three includes, but there is still an error.

Each of the three includes can contain many further lookups. The SPF checker shows the total.