← Back home

2026.08 / SPF troubleshooting 038

Fix SPF PermError: Too Many DNS Lookups in Docker Mailserver

Your SPF TXT record looks short, but Gmail or another receiver reports spf=permerror, often with “too many DNS lookups.” The visible record is only the start. Every nested include:, redirect=, mx, or other DNS-querying term can expand into more work.

RFC 7208 gives an SPF evaluation at most 10 terms that cause DNS queries. Exceeding that processing limit returns permerror. This is not a Docker networking problem, and restarting Docker Mailserver will not repair a sender policy published in public DNS.

The safe fix is to inventory real sending routes, count the complete recursive policy, and simplify it without silently unauthorising mail.

First separate outbound SPF from inbound SPF checking

Two different controls are easy to confuse:

Changing ENABLE_POLICYD_SPF, restarting the container, or changing a local spam score does not alter the SPF record Gmail sees for your outbound mail. Edit the authoritative DNS policy only after mapping every legitimate sender.

1. Capture the exact failed identity

SPF authenticates the RFC5321 envelope sender (or HELO identity when the reverse path is empty), not automatically the visible From address. Save the recipient’s original message or rejection and identify:

Keep raw messages and logs private. They can contain addresses, internal names and delivery identifiers. Redact a copy before sharing evidence.

2. Confirm there is exactly one SPF record

Query public recursive resolvers rather than trusting a DNS dashboard:

dig +short TXT example.com @1.1.1.1
dig +short TXT example.com @8.8.8.8

Replace example.com with the envelope-sender domain. A domain must not publish two separate v=spf1 records. Merge authorised sources into one policy; do not add a second record as a quick fix.

3. Count the recursive SPF path, not just the first line

RFC 7208 section 4.6.4 counts these mechanisms and modifiers toward the 10-term limit when evaluated:

TermUses the SPF lookup budget?Practical note
include:YesIts nested policy can consume several more terms.
a, mxYesAddress resolution follows; broad mx use can be expensive.
exists:YesOften hidden inside vendor policies.
redirect=YesThe redirected policy must also be evaluated.
ptrYesRFC 7208 says it should not be used because it is slow and unreliable.
ip4:, ip6:, allNoThese do not trigger SPF DNS-querying terms.

The budget is route-dependent because SPF evaluation stops when a mechanism matches. Nevertheless, every legitimate route must remain within the limit. Also note RFC 7208’s separate limit of two “void lookups”—queries returning an empty answer or name error.

Expand every include yourself and keep the chain visible:

# Start at the envelope-sender domain
host -t TXT example.com

# Then query each include or redirect discovered in the answer
host -t TXT _spf.sender-service.example
host -t TXT nested-policy.sender-service.example

Use the provider’s real documented SPF hostname in your DNS, not these placeholders. Do not count TXT queries mechanically as if each response were one term: count the DNS-querying SPF mechanisms encountered across the evaluated tree.

4. Build a sender inventory before deleting includes

For each mechanism, record the business owner, envelope-sender domain, service, last known use, and evidence. Typical sources include:

Use recent Postfix logs, provider configuration, received-message headers and DMARC aggregate reports. Absence from one day of logs is not proof that an annual billing system or password-reset route is obsolete.

5. Simplify in the least fragile order

  1. Remove confirmed obsolete services. Disable the sender first or prove it has already been retired, then remove its include.
  2. Remove duplicates and redundant mechanisms. Do not authorise the same source through several nested vendors.
  3. Use direct ip4: or ip6: only for addresses you control and keep stable. A directly delivering VPS may need one explicit address, while a managed sender should normally use its supported include.
  4. Separate mail streams with subdomains. For example, transactional and marketing return paths can have distinct SPF policies and operational owners.
  5. Ask a provider for its supported compact policy. Do not invent an internal include hostname or copy a record from an old tutorial.

Why manual SPF flattening is not the default fix

“Flattening” replaces includes with their current IP addresses. It can reduce DNS-querying terms, but it transfers responsibility for tracking vendor IP changes to you. A static copy can silently go stale and fail legitimate mail later.

If a service’s addresses are dynamic, retain its documented include or use a managed, monitored method with automatic refresh, change alerts and rollback. Never paste a third-party website’s flattened result into production without confirming ownership and update behaviour.

6. Publish carefully and verify publicly

Before changing DNS, save the old record and reduce TTL in advance if your change process permits it. Publish one SPF record, then query multiple public resolvers until the intended value is visible. Do not expose unrelated DNS records or real infrastructure addresses in screenshots.

For a simple server that sends directly and has no other sender, a conceptual policy may look like this:

v=spf1 ip4:192.0.2.10 -all

192.0.2.10 is a documentation-only address. Use only the real authorised source in private DNS administration. If legitimate services remain, include their provider-documented mechanisms in the single policy and recount the full tree.

7. Send a fresh message and prove DMARC alignment

DNS syntax tests are not enough. Send one new controlled message through each legitimate route to a mailbox you own. Inspect the received original and require evidence such as:

Authentication-Results: receiver.example;
  spf=pass smtp.mailfrom=bounces.example.com;
  dkim=pass header.d=example.com;
  dmarc=pass header.from=example.com

For DMARC, an SPF pass contributes only when the authenticated envelope-sender domain aligns with the visible From domain. A valid but unaligned SPF result can coexist with dmarc=fail. Aligned DKIM can independently satisfy DMARC, but it should not be used to excuse a broken SPF policy.

Match each test to its Docker Mailserver queue ID and remote 250 response. Test every authorised service—not merely direct VPS delivery—because different branches of the SPF tree can consume different lookup counts.

Common wrong turns

Compact recovery checklist

  1. Identify the failed envelope-sender domain and exact receiver result.
  2. Confirm public DNS contains exactly one v=spf1 record.
  3. Expand every include and redirect; count all recursive DNS-querying terms.
  4. Inventory direct mail, relays and third-party senders before removing anything.
  5. Remove obsolete and redundant sources; avoid ptr and fragile manual flattening.
  6. Publish one simplified policy and verify it through public resolvers.
  7. Send fresh mail through every legitimate route.
  8. Require spf=pass plus aligned dmarc=pass, or investigate the remaining identity mismatch.

The authoritative limit and evaluation rules are in RFC 7208 section 4.6.4. For implementation context, use Docker Mailserver’s current DKIM, DMARC and SPF documentation and the documentation matching your pinned image.