Why I made the SPF generator care about the lookup budget
Marc's note on the product choice behind our SPF generator: show the lookup budget early, treat provider presets carefully, and never pretend a browser estimate is live DNS validation.
Standards basis: SPF lookup-limit guidance based on RFC 7208. DMARC alignment notes are based on RFC 9989 for DMARC policy records.
I have a small allergy to SPF generators that hand you a string too quickly.
The easy version is a checklist of providers, a text box for IPs, and a copy button. It feels helpful. It also creates a very clean-looking DNS record that can fail the moment a receiver evaluates it.
SPF has one hard constraint that people meet late: a receiver is allowed to evaluate only 10 DNS-querying terms. That includes include, a, mx, ptr, exists, and redirect. Go past that, and SPF returns a permanent error. For DMARC, that means SPF stops helping.
So the first real product decision in our SPF generator was not the provider list. It was the counter. The lookup budget has to sit in front of you while you are building the record, before the copy button becomes tempting.
The generator is intentionally conservative
A common SPF generator pattern is the giant provider buffet:
- Google Workspace
- Microsoft 365
- SendGrid
- Mailchimp
- HubSpot
- Zendesk
- every tool anyone has ever used to send one email
I understand why those tools do it. It looks complete. But it trains the wrong reflex. People select every vendor they recognize, even when that vendor does not belong in the root-domain SPF record for their setup.
SPF checks the envelope sender domain, also called the Return-Path or MAIL FROM domain. It does not check the visible From: header your recipient sees.
That distinction matters in a very practical way. Many transactional and marketing platforms use their own Return-Path domain by default and rely on DKIM alignment for DMARC. In that mode, adding the provider’s SPF include to your root domain may do nothing useful for DMARC. It still spends lookup budget.
This is why the generator separates common root-domain includes from setup-dependent providers. I would rather make someone pause for 15 seconds than help them build a pretty invalid record in five.
Why the lookup count is an estimate
The lookup counter is useful, but I do not want to oversell it.
The Stimulus controller runs in the visitor’s browser. It can read the checked boxes, parse custom includes, validate IP syntax, assemble the SPF string, and count the lookup cost we know from the form state. It cannot do the same recursive DNS evaluation a receiving mail server does when real mail arrives.
That tradeoff is deliberate. The generator should be fast and private; it should not need to send your draft DNS record to our servers just to update a form. The price is that the counter is a design-time guardrail, not an authoritative DNS trace.
After publishing, use the domain checker. That is where server-side DNS checks run against the record the internet can actually resolve. It sees current provider includes, nested records, DNS errors, and the odd surprise your DNS host may introduce.
When the live lookup fails because DNSSEC validation is broken, the SPF text is not the thing to fix. Use the DNSSEC checker to confirm the delegation and signatures before changing the SPF record.
I am fussy about that split. The generator helps you avoid bad choices before publishing. The checker tells you what the world can resolve after publishing. Those are different jobs.
Why copying gets blocked over the limit
When the estimated lookup count goes above 10, the copy button is disabled.
That is a small product decision, and I am stubborn about it. A warning that still lets you copy the broken thing is easy to ignore. Most people are in a DNS provider tab, tired, with another tab open that says something like “add this TXT value.” If the tool knows the draft is likely to fail, it should stop pretending the record is ready.
The generated string still appears so you can inspect it. The record container turns into an error state. The counter turns red. But copying is blocked until the draft comes back under budget.
The Stimulus controller handles that without much ceremony. It watches provider checkboxes, custom includes, deprecated mechanisms, and IP fields. On each input event it rebuilds the record, updates the counter, and toggles the copy state.
Simple code. The important part is the pressure it puts on the decision.
The length warning is separate from the lookup warning
SPF has another practical failure mode: the TXT value becomes too long.
DNS TXT records can be represented as multiple quoted strings, but plenty of DNS dashboards make that detail easy to mishandle. Long SPF records are also hard to review. If the record grows past a comfortable size, the generator warns you even when the lookup count is under 10.
That catches a different problem. Direct ip4: and ip6: mechanisms do not spend DNS lookups, which is good. But dumping dozens of IP ranges into the root record creates a record nobody wants to maintain.
That is where SPF flattening becomes an operational question, not a generator feature. If you keep trading includes for piles of IPs, read the SPF optimizer article. The generator helps you write one record. The harder problem is keeping that record healthy when providers change their infrastructure.
Why a, mx, and ptr are behind the warning door
The generator includes a “legacy mechanisms” section. It is collapsed, and it looks a little unfriendly on purpose.
The a mechanism looks convenient: authorize the IP address of this domain’s A record. The mx mechanism looks convenient too: authorize the hosts that receive mail for the domain. Both spend lookup budget, and both create coupling that many domain owners do not intend. Website hosting and outbound mail are often unrelated. Inbound mail exchangers and outbound senders are often unrelated too.
The ptr mechanism is worse. RFC 7208 says it should not be published. It is slow, DNS-expensive, and fragile. I still keep it visible in the advanced section because people encounter old SPF records and need to understand what they are looking at. The tool should not make it feel normal.
Good tools do not give every option the same weight. Some options are common. Some are advanced. Some are there because email history is long and not always kind.
The all-mechanism default is a product opinion
The generator defaults to ~all.
Some security people prefer -all immediately. I understand the instinct. I also know what happens when a small business has three forgotten senders and someone publishes a strict SPF record after a quick web search.
With DMARC in the picture, SPF is only one authentication path. DKIM often carries alignment for third-party senders. Starting with ~all gives the domain owner a safer place to validate the sender inventory before tightening.
The tool still offers -all. It should. Some domains are simple, controlled, and ready for it. But the default should match the messy reality I see most often: old CRMs, ticketing systems, web forms, marketing platforms, and one SaaS trial nobody remembers.
What I hope people notice
The SPF string is the artifact. The mental model is the part I care about.
If someone leaves the page with only a few ideas, I hope they are these:
- SPF has a hard DNS lookup budget.
- Provider includes belong only where the provider’s Return-Path setup makes them relevant.
- Browser-side generation is a draft; live DNS validation is the truth.
That is a different goal from “make a free SPF record in one click.” One-click tools are nice until they teach people to stop thinking at the exact point where DNS needs care.
Marc