Skip to content

Build1 publisher3 min readPublished

Counting the full SPF include tree nightly catches the vendor include that breaks your record

The DNS and header half of deliverability is a pure function of your own configuration, so a scheduled job can assert it; inbox placement is a measurement you put on a dashboard with a date on it.

The Engineer · Build desk

Illustration accompanying Counting the full SPF include tree nightly catches the vendor include that breaks your record

What happened

  • A dev.to post splits deliverability testing into a deterministic question, whether you sent a well-formed authenticated message, and a question decided by a receiver's classifier using your sending history.
  • Its example tests assert that the domain publishes exactly one SPF record and that a recursive walk of the include tree stays within the 10 DNS lookup limit.
  • The DNS checks are recommended as a nightly job against production DNS rather than a deploy gate, because the record can break on a day nobody shipped code.
  • Inbox placement, reputation and spam-word scoring are put on a dated dashboard, with the build gated on none of them.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Adding a sending vendor spends part of a 10-lookup budget that third-party records also draw on, so DNS caps the decision to integrate one more service, alongside the contract.
  • decision The check has to live in a scheduler with its own alerting, because a pipeline that only runs on commit cannot observe a break caused by someone else's DNS edit.
  • capability Asserting the signing domain turns a green DKIM check into evidence about alignment. Alignment is the part a DMARC evaluation actually consumes.

The 10-lookup limit is not a property of your SPF record alone. The test in the dev.to post calls `count_lookups`, which walks includes recursively, and asserts the total stays at or under 10 [3]. Your own record contributes some of those lookups. The rest sit inside records owned by third parties, and the budget is charged against your domain either way [20]. A vendor adds one include inside their record, your domain goes over, and nothing in your repository changed [4].

So the post moves the DNS checks off the deploy path and onto a nightly schedule against production DNS, because the failure arrives on a day you did not ship anything [5]. It does not report how often vendor includes push a domain over the limit [22].

The other deterministic half is your own output, asserted before it leaves the building. The post's list: a `List-Unsubscribe` header plus `List-Unsubscribe-Post` for one-click, a `Message-ID` containing your sending domain, a plain-text alternative that is neither empty nor stripped HTML, a `From` that aligns with the domain you intend to sign with, and no unsubscribe link pointing at `localhost` [6]. On that last one the author writes that it "ships more often than anyone admits" [7].

Then one real message to a mailbox you control, with the assertion on the `Authentication-Results` header the receiver stamped [8]. The example shows `spf=pass`, `dkim=pass [email protected]` and `dmarc=pass` [9]. The post instructs you to assert on the `d=` or `header.i=` value, not only the verdict: a `dkim=pass` carrying your ESP's domain aligns with nothing, DMARC fails anyway, and every "is DKIM working?" check reports it as fine [10].

In the deterministic half, everything fails for a reason you can fix; past it, the verdict belongs to someone else. Gmail's choice between Primary, Promotions and Spam depends on your domain's history, the recipient's own behaviour, and a classifier that changes without notice [11]. Seed-list tools sample placement from mailboxes with no real engagement history, the input the classifier weighs most heavily; the post treats the sample as a trend, not a gate [12]. Reputation is a lagging aggregate with no assertion to write [13]. Content is real but the smallest factor, and the scores are not the receiver's scores. The post says rewriting subject lines is the first thing people try and the last thing that helps [14]. It gates the build on none of it and puts it on a dashboard with a date [21].

One more constraint shapes the whole setup: the cheapest mistake in the area is a staging environment that can reach the open internet [15]. The remedy is to make a catching SMTP server the default for non-production, MailHog, Mailpit or the provider sandbox, so that reaching a real recipient requires an explicit override [16]. If production credentials exist anywhere in a non-production environment, one seeded fixture with real addresses is enough to send [17]. The related rule is not to warm a domain with test traffic, since warm-up is a claim about human sending behaviour and synthetic volume against seed mailboxes teaches the receiver something else [18].

For the DNS half specifically, the post points at spf-audit as the CI-shaped tool: it walks the full include tree and exits non-zero over the limit [19].

What to watch

  • Whether large receivers stamp more of their alignment reasoning into Authentication-Results. That would extend what a single real send can assert.
  • Whether one-click unsubscribe requirements move beyond List-Unsubscribe-Post and change the header assertion list.
  • Whether spf-audit keeps a stable non-zero exit contract as its include-walking logic changes, since a scheduled job depends on that exit code.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories