Understanding and correctly implementing SPF flattening and DNS lookup limits for mail servers

SPF Flattening reduces the number of DNS queries of an SPF record so that mail servers comply with the strict 10-lookup limit and no permerror risks arise [4][6]. I show how I analyze the relevant mechanisms, enter IPs directly and thus Delivery, performance and DMARC alignment [1][9].

Key points

I will briefly summarize the most important aspects before going into greater depth and explaining the necessary steps in detail; this way, beginners and professionals alike can keep the Overview and implement changes in a targeted manner.

  • Lookup limitMaximum of 10 SPF DNS queries per test [4][6]
  • Causes: Too many include-, a-, mx-mechanisms and cascades
  • FlatteningReduce hostname to ip4/ip6, avoid permerror
  • Maintenance: Regularly update changes to provider IPs
  • Overall setupCombining SPF with DKIM and DMARC makes sense

I use these points as a guide to keep SPF records lean and Error in the delivery chain at an early stage.

SPF briefly explained

SPF (Sender Policy Framework) authenticates the sending server via a TXT record in the DNS and specifies which systems are allowed to send on behalf of the domain [2][3][6]. A typical entry is: v=spf1 a mx ip4:203.0.113.10 include:_spf.provider.de ~all, whereby the mechanisms determine which sources are permitted and the qualifier controls the behaviour for unauthorized persons [3][6]. I make sure that ip4/ip6 replace as many hostnames as possible because these variants do not trigger any further DNS queries [4][6]. This keeps the record clear and prevents unnecessary dependencies on name servers, which can cause additional delays during peak loads [4]. Used correctly, a clean SPF record strengthens delivery, supports the domain reputation and complements DKIM and DMARC make sense [1][6][9].

Why DNS lookups count

Every message received triggers an SPF check, which includes mechanisms such as include, a, mx, exists or the obsolete ptr to DNS lookups [4][6]. The rules limit these queries to a maximum of ten in order to limit abuse and latency [4][6]. If a record exceeds this limit, recipients often report a permerror and evaluate the email negatively, which reduces delivery and inbox hits [4][6][8]. I therefore consistently analyze which entries generate new queries and remove duplicate references or unnecessary chains before planning further changes. This is how I keep the Performance of the infrastructure and minimize sources of error that only become apparent under load.

Common causes for too many lookups

Too many include-mechanisms quickly bloat records, especially when several SaaS services, newsletter tools and ticket systems send in parallel [4][7]. Cascading includes are treacherous because a single reference loads further rules and thus reaches the limit almost unnoticed [4][7]. a and mx also increase the queries as soon as they point to host names, which in turn have to be resolved into several IPs [4]. Today, the ptr mechanism is considered insecure and expensive to resolve and no longer has a place in current setups [1][4]. I therefore check each entry for its lookup effect and consolidate mechanisms before talking about optimization.

SPF Flattening: Concept and benefits

At Flattening I reduce all hostnames and includes to fixed ip4/ip6 entries so that no additional DNS queries are created [4][6]. In this way, a previously nested record with several providers shrinks to a short list of IPs that does not need to be looked up [4][6]. The benefits are immediate: fewer queries, less risk of permerror and better delivery to strict recipients [8][9]. I keep the structure clear and remove duplicate nets so that interpretation remains easy for tools and postmasters. This approach provides a transparent view of the actual senders and speeds up debugging.

Risks and maintenance

Flattening comes at a price because external providers can change their shipping IPs and then a flat Record out of date [1][4]. I therefore schedule fixed update cycles and document which entry belongs to which service. If networks are missing or IP blocks slip out of the list, legitimate messages fall through the check and put unnecessary strain on the reputation. To avoid this, I link every change to a test run and keep the history of the networks to hand [4][6]. In this way, I secure the advantages of flattening without overlooking the maintenance obligation.

Best practices before flattening

Before each intervention I take an inventory of all systems that send on behalf of the domain: Mail servers, web and app servers, marketing tools and cloud services [3][4][6]. Only these sources belong in the SPF record; I consistently leave out receiving systems or purely internal hosts [4][6]. I only reference each server once and only use mx if these systems are actually sending outgoing messages [4]. Where addresses rarely change, I write ip4/ip6 directly and avoid host names that trigger new queries [4][6]. For a more detailed overview of the interaction with Serverauth, please refer to SPF, DKIM and DMARC in hosting, which often saves me time in practice.

Flattening step by step

I start with a Analysis of the current TXT record and count all lookup-relevant mechanisms including nested includes [4][6]. I then completely resolve hostnames and includes to IPs and check whether the networks are officially documented. I then replace include, a and mx mechanisms with ip4/ip6, remove duplicates and group entries logically [4]. Depending on the risk, I choose ~all or -all for the all mechanism, depending on redirects and the clarity of the sender paths [3][6]. If you use an admin panel, you will find the Plesk instructions Additional handles for clean rollouts.

SPF, DKIM, DMARC in interaction

An SPF record works best when DKIM is actively signed and DMARC evaluates the results consistently [1][9]. DMARC checks whether SPF or DKIM exist and whether the visible from-domain matches the checked domain (alignment) [9]. If SPF fails due to permerror, DMARC also fails in many setups, even though the content is actually legitimate. I therefore pay attention to clear sender paths and consistent domains in headers, signatures and SPF data. If you want to take a structured approach to alignment, you can use SPF alignment and DMARC and thus avoid incorrect valuations.

DNS strategy, TTL and operation

An SPF record lives in a DNS-zone, which I keep clean so that debugging and changes are easy [1]. I set sensible TTL values, often between one and a few hours, to make rollouts predictable and cache behavior predictable [1][3]. After changes, I check the result with tools and monitor DMARC reports to detect anomalies early [1][9]. I remove obsolete A, AAAA, MX and TXT records so that no side effects occur that are difficult to assign later [1]. This discipline saves me time in everyday life and stabilizes the Delivery measurable.

Table: Mechanisms and lookup costs

This compact overview helps me to quickly categorize which Mechanisms DNS queries and which do not; this allows me to quickly decide where flattening has the greatest effect [4][6].

mechanism Triggers DNS lookups? Notes
ip4 / ip6 No Direct IPs, no additional queries, ideal for Flattening [4][6]
a Yes Resolves host names into IPs; the number of queries increases with many hosts [4]
mx Yes Only useful if MX servers also send outgoing data; otherwise omit [4]
include Yes Can reload chains and quickly reach the 10 limit [4][7]
exists Yes Generates additional queries; use sparingly [4]
ptr Yes Outdated and unsafe; I consistently avoid it [1][4]

Mechanisms, sequence and qualifiers

To ensure that an SPF record works reliably, I select the Sequence aware of the mechanisms. First I will mention the most specific sources (ip4/ip6 of individual hosts, small networks), then broader networks and finally generic rules. The all-mechanism, I always use the End, so that it does not „cover“ anything. Qualifiers control the sharpness: - (fail) blocks hard, ~ (softfail) marked as suspicious, + is standard (pass) and ? is neutral [3][6]. In my day-to-day business, I often work with ~all, to cushion rollouts, and set up a clean inventory on -all um. Caution with mx and a: They are comfortable, but expensive in lookups. Where possible, I replace them with ip4:/ip6: and spare queries [4][6].

include vs redirect and structure for subdomains

include inserts third-party rules into the current record and counts towards the lookup budget for each check [4][7]. redirect (as a modifier) redirects the complete evaluation to another SPF record and is useful for centralizing policies. bundle - for example if all subdomains use the same sender. For clearly separated setups, I give individual subdomains (z. B. mail.example.de or bounce.example.de) own SPF records so that DMARC alignment can be planned [9]. I avoid „cascades“ of several include-levels because they eat up the 10 limit invisibly. Where possible, I consolidate to a „policy hub“ via redirect= and write down the actual sender networks there as IPs.

Limits, lengths and DNS answers

In addition to the lookup limit Length restrictions plays a role. TXT records consist internally of strings up to 255 characters; I therefore split long SPF entries into several quotation blocks. I keep the total length moderate so that responses are not unnecessarily fragmented. I also pay attention to „void lookups“: DNS queries that do not return any data can trigger additional error conditions depending on the implementation [4][6]. A second technical stumbling block are duplicate SPF records per hostname - this leads to permerror. I therefore only ever leave a SPF TXT record per domain/subdomain and clean up legacy data.

Practical examples: Before/after flattening

In practice, many setups start like this:

v=spf1 a mx include:_spf.provider-a.com include:_spf.provider-b.com include:spf.newsletter.com ~all

At first glance, everything seems correct, but the includes often load additional includes. If I count, 10 lookups are quickly reached or exceeded. After flattening, the same policy looks much leaner:

v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 ip4:198.51.100.0/24 ip6:2001:db8:1234::/48 ~all

Here I have the a/mx-mechanisms and the includes are completely broken down into IPs and networks, duplicates are removed and networks are combined in a meaningful way. If a service uses both v4 and v6, I enter both - this prevents messages via IPv6 from suddenly failing even though IPv4 is enabled. Important: I document each, which IP belongs to which service so that subsequent changes and audits are easy.

Forwarding, SRS and mailing lists

SPF evaluates the Envelope-From (return path). Redirects are often sent by an intermediate server that is not authorized in the original domain. Without SRS (Sender Rewriting Scheme), SPF then fails - regardless of how well the SPF record is maintained [3][6]. I therefore check whether forwarders use SRS or whether alternative methods (e.g. direct delivery) are practicable. Mailing lists also change headers and can break DKIM; here it helps to keep SPF stable and configure DKIM in such a way that list software does not damage signatures unnecessarily. With DMARC in relaxed alignment, I avoid unnecessary rejections as long as sender paths are clear [9].

Automation, monitoring and rollback

Flattening brings Maintenance effort. I rely on recurring tasks that resolve provider records into IPs, sort them, normalize them (CIDR) and compare them with my productive record. If I detect deviations, I plan a change with a short TTL, execute it in stages and monitor logs and DMARC reports [1][9]. A clean Rollback is part of this: Before every change, I back up the DNS zone, noting the date, responsible systems and the reason. In dynamic environments, I encapsulate third-party providers own subdomains (e.g. mailings.example.de) so that I can make adjustments in isolation and limit risks. This keeps the main SPF of the root domain lean, while special cases evolve separately.

Troubleshooting: tools and typical diagnoses

In the event of problems, I first check whether multiple SPF records exist - this immediately generates permerror. Then I count lookups: Which mechanisms trigger queries, where do includes cascade? With dig/nslookup I check resolutions of individual hostnames and count IPs per a/mx-target. Test mails to strict recipients are also helpful in order to see real evaluation paths. Common causes are: incorrectly set qualifiers (all too high), forgotten IPv6 shares, list software without SRS on forwarders, and admin panels that add additional includes unnoticed. I fix this step by step, testing after each intervention and documenting the effect - so the setup stays that way predictable and reproducible.

IPv6, network summary and clean notation

Where possible, I group individual IPs into CIDR networks together as long as the semantic meaning does not change. This reduces characters and keeps the record readable. With IPv6, I prefer to enter the official sending prefixes of the providers and check whether my MTA actually delivers via v6. If v6 connections are actively used, the SPF record must explicitly allow these networks - otherwise there is a risk of inconsistent results depending on the transport route. I also pay attention to clear notation (no mixed spellings, consistent sorting) to reduce human error in subsequent edits.

Change management and collaboration

SPF is not a stand-alone topic: sales, marketing, support and development often launch new systems with their own e-mail function. I therefore establish a Release processBefore a service goes live, I check its sender path, required IP ranges and the interaction with DKIM/DMARC. I communicate changes to the SPF record in advance, set an adjusted TTL for the maintenance window and reactivate longer TTLs for stability after the go-live [1][3]. This coordination prevents surprises during live operation and keeps the domain's reputation high.

Current articles