# How do I fix SPF PermError: too many DNS lookups?

> SPF PermError: too many DNS lookups means your record needs more than 10 DNS queries. Here is how to count your lookups and get back under the limit.

An SPF `PermError: too many DNS lookups` means evaluating your SPF record required more than **10 DNS-querying mechanisms**, the hard cap set by [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208). Once you cross it, the whole record returns `permerror` and most receivers treat SPF as failed — so mail you actually authorized can start landing in spam or bouncing. You fix it by counting the lookups each `include`, `a`, and `mx` adds, then trimming, consolidating, or replacing them with `ip4`/`ip6` mechanisms until you are back under 10.

## Quick Takeaways

- The limit is **10 DNS lookups per SPF evaluation**, counting nested lookups inside every `include`, defined by [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208).
- Counting mechanisms: `include`, `a`, `mx`, `ptr`, `exists`, and the `redirect` modifier. `ip4`, `ip6`, and `all` cost nothing.
- Nested `include`s are the usual culprit — one provider's `include` can hide four or five lookups.
- There is a second, quieter cap: **2 void lookups** (queries that return no record) also trigger `permerror`.
- Fix it by removing unused senders, replacing stable `include`s with `ip4`, and delegating high-volume senders to subdomains.
- `PermError` is a permanent failure — receivers do not retry it, so it silently degrades deliverability until you fix the record.

## What causes an SPF PermError: too many DNS lookups?

Every time a receiver checks your SPF record, it has to resolve each mechanism that points at a name rather than a raw IP. To stop one message from triggering an unbounded chain of DNS queries, [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208) caps that chain at **10 DNS-querying mechanisms**. Exceed it and evaluation halts with `permerror` — the record is treated as broken, not as a pass or fail.

The mechanisms that count against the limit are:

| Term | Counts as a lookup? | Notes |
|---|---|---|
| `include:` | Yes | Also counts every lookup *inside* the included record, recursively |
| `a` | Yes | Resolves the domain's A/AAAA record |
| `mx` | Yes | One lookup, plus resolution of each returned MX host |
| `ptr` | Yes | Deprecated — avoid entirely |
| `exists:` | Yes | Advanced macro mechanism |
| `redirect=` | Yes | The modifier that hands off to another record |
| `ip4:` / `ip6:` | No | Raw addresses need no DNS query |
| `all` | No | The catch-all costs nothing |

The trap is recursion. When you add `include:_spf.google.com` or a marketing platform's `include`, you are not spending one lookup — you are spending one *plus* every lookup that provider's own record contains. A handful of third-party senders can quietly push a record past 10 even though it only *looks* like five or six entries. If you are still learning how these terms fit together, our [SPF record syntax guide](/learning/spf-record-syntax-explained-mechanisms-qualifiers) breaks down every mechanism and qualifier.

## What is the SPF void lookup limit?

There is a second cap that catches people out. [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208) also limits **void lookups** — DNS queries that return `NXDOMAIN` or an empty answer — to **2** per evaluation. Go over that and you also get `permerror`, even if your total lookup count is well under 10.

Void lookups usually mean a mechanism points at a hostname that no longer resolves: a decommissioned mail server referenced by an `a` mechanism, or an `include` for a service whose SPF record was deleted when you closed the account. Because the symptom is identical (`permerror`), a record that passes a raw lookup count can still fail on void lookups — check both.

## How do I count my SPF DNS lookups?

You cannot eyeball it reliably, because the expensive lookups are hidden inside the `include`s. Two dependable ways to get the real number:

1. **Use a checker that expands includes.** Palisade's [SPF checker](/tools/spf) resolves your record the way a receiver does, counts every nested lookup, and shows which `include` is pushing you over. A raw [DNS lookup tool](/tools/dns-lookup) confirms what a given `include` actually resolves to.
2. **Trace it by hand.** Query each `include`'s TXT record and add up the counting mechanisms inside it, then repeat for any nested `include`s. Tedious, but it shows exactly where the budget goes.

Do the count *before* you change anything, so you know how many lookups you need to reclaim. If a single provider's `include` accounts for five of your ten, that is where the fix has the most leverage.

## How do I fix "too many DNS lookups"?

Work through these in order — cheapest and safest first.

1. **Remove senders you no longer use.** Every `include` from a retired newsletter tool, a trial you never adopted, or an old CRM is pure waste. Audit the list against services you actually send from today and delete the rest. This is often enough on its own.
2. **Replace stable `include`s with `ip4`/`ip6`.** If a service publishes a small, fixed set of sending IPs, list those addresses directly instead of its `include`. Raw IP mechanisms cost zero lookups. The trade-off: if that provider changes its IPs, your record goes stale, so only do this for senders with genuinely static ranges — and re-check periodically.
3. **Consolidate senders.** Route several tools through one platform where you can, so you carry one `include` instead of four. Fewer sending services means a leaner record.
4. **Delegate heavy senders to a subdomain.** Send bulk or marketing mail from `mail.yourdomain.com` or `news.yourdomain.com`, each with its own SPF record. The subdomain gets its own fresh 10-lookup budget, and your primary domain's record stays small. Keep DMARC alignment relaxed so the subdomain still aligns for [DMARC](/learning/what-is-dmarc).
5. **Drop `ptr` entirely.** [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208) explicitly discourages `ptr` — it is slow, unreliable, and burns a lookup. Remove it and authorize those senders another way.

After each change, re-check the count. The goal is comfortably under 10 (aim for 8 or fewer) so you have headroom when a provider adds a lookup to its own record later.

## Is SPF flattening a safe fix?

"Flattening" means resolving your `include`s down to their underlying IPs and hard-coding those as `ip4`/`ip6`, producing a record that costs zero lookups. It reliably kills `permerror`, but it moves the maintenance burden onto you: the moment a provider rotates its sending IPs, your flattened record authorizes the wrong addresses and legitimate mail starts failing SPF — often silently.

Flattening is defensible for senders with stable, published IP ranges, and risky for large providers (Google, Microsoft) whose ranges shift. If you flatten, you need a process to re-resolve and update the record on a schedule, not a one-time paste. For most domains, trimming unused `include`s and delegating to subdomains fixes the problem without taking on that upkeep.

## Common issues with SPF PermError

### The record looks short but still throws permerror

Length is not the same as lookup count. A record with only four visible `include`s can exceed 10 because each `include` pulls in nested lookups. Expand every `include` — with the [SPF checker](/tools/spf) or by querying each TXT record — and add up the hidden lookups, not the visible mechanisms.

### There are two SPF records on the domain

A domain may publish exactly **one** SPF record. Two `v=spf1` TXT records do not merge; they produce a `permerror` and invalidate each other. Combine everything into a single record: one `v=spf1`, all your `include`s and IPs, one closing `all`.

### PermError from a void lookup, not the count

If your lookup count is under 10 but you still see `permerror`, check for **void lookups** — `include`s or `a`/`mx` mechanisms pointing at hostnames that no longer resolve. More than two of them triggers the error. Remove references to dead servers and closed-account services.

### You fixed the record but receivers still see the error

DNS caches. After you edit the TXT record, resolvers and receivers may serve the old version until its TTL expires. Give it time to propagate, then re-test — do not keep editing on the assumption the fix did not work. A [DNS lookup tool](/tools/dns-lookup) shows the currently published value so you can confirm the change is live.

## Frequently asked questions

### Does a PermError mean my email will bounce?

Not always, but it is treated as an SPF failure. Many receivers accept the message and lower its reputation; stricter ones — and any domain relying on SPF for [DMARC](/learning/what-is-dmarc) alignment — may quarantine or reject it. Because `permerror` is *permanent*, receivers do not retry, so the damage is consistent until you fix the record.

### Does the 10-lookup limit apply to DKIM too?

No. The 10-lookup cap is SPF-specific. [DKIM](/learning/what-is-dkim) uses a single DNS lookup to fetch the signing key and has no equivalent limit. If your authentication problem is a DKIM signature failure rather than SPF, that is a separate issue with separate fixes.

### Can I just switch to ~all to hide the error?

No. The `all` qualifier controls what happens to *unlisted* senders; it does not change the fact that the record is malformed. A `permerror` overrides the qualifier — receivers see a broken record regardless of whether you end with `~all` or `-all`. You have to reduce the lookups.

### How much headroom should I leave under the limit?

Aim for 8 lookups or fewer. Providers occasionally add a lookup to their own SPF records, and a domain sitting at exactly 10 can tip into `permerror` without you touching anything. A couple of spare lookups absorbs that drift.

Palisade automates this for teams juggling many client domains: it counts SPF lookups continuously, flags a record before it crosses the limit, and rolls SPF, DKIM, and DMARC into a single health check. You can run that same check now with the free [Email Security Score](/tools/email-security-score) tool to see where every domain stands.

## Related reading

- [SPF record syntax explained: mechanisms and qualifiers](/learning/spf-record-syntax-explained-mechanisms-qualifiers)
- [What is SPF and how does it work?](/learning/what-is-spf)
- [Why DMARC fails and how to fix it](/learning/why-dmarc-fails-how-to-fix-it)
