What the generator is assembling
An SPF record is a single line of space-separated terms inside one TXT record. It always starts with the version tag v=spf1 and almost always ends with an all mechanism. Everything between them is the authorised-sender list, evaluated left to right until one term matches the connecting IP address. A finished record for a company on Google Workspace that also sends transactional mail through SendGrid looks like this:
v=spf1 ip4:203.0.113.10 include:_spf.google.com include:sendgrid.net ~allThe generator puts ip4: and ip6: terms first on purpose. Those match with zero DNS traffic, so a message from your own mail server is authorised before the evaluator touches a provider record at all. It is a small efficiency, but it also makes the record easier to read: your infrastructure first, third parties second, policy last.
Choosing terms: what each one costs
| Term | Authorises | DNS lookups |
|---|---|---|
ip4:203.0.113.0/24 | An IPv4 address or CIDR range | 0 |
ip6:2001:db8::/32 | An IPv6 address or CIDR range | 0 |
include:_spf.google.com | Everything in another domain's SPF record | 1 + whatever that record itself spends |
a | The A/AAAA addresses of this domain | 1 |
mx | The addresses of this domain's MX hosts | 1 (plus up to 10 address lookups) |
ptr | Hosts whose reverse DNS matches — deprecated | 1, and receivers may ignore it |
exists:%{i}._spf.example.com | Macro-expanded existence test | 1 |
~all / -all | Everyone else | 0 |
Read the full explanation of spf record generator results ↓Show less ↑
Prefer ip4: over a and mx whenever your addresses are stable. a and mx each cost a lookup from the ten you are allowed, and both silently authorise whatever those records happen to point at — if your MX moves to a filtering service, mx now authorises the filter's inbound hosts, which is rarely what you meant. The cPanel-style +a +mx preset in the generator is the traditional shared-hosting answer and it works, but on a stable VPS two ip4: terms are cheaper and more precise.
ptr. RFC 7208 §5.5 formally deprecates it: it is slow, it burdens the receiver with reverse lookups, and some receivers skip it entirely, which turns a mechanism you rely on into a no-op.The 10-lookup budget you are spending
The generator shows how many lookup-consuming terms this record contains. That number is a floor, not the total. Each include: pulls in a provider record that spends more of the same budget — some providers use one lookup, others chain three or four. Ten is the hard ceiling across the entire tree (RFC 7208 §4.6.4), and crossing it makes receivers return PermError, which Gmail, Outlook and Yahoo treat as an SPF failure. Publish the record, wait for the TTL, then run the SPF checker to see the real recursive count.
Practical budgeting: with Google Workspace plus two ESPs you are typically in the 5–8 range and fine. Add a helpdesk, an invoicing tool, a marketing platform, and a webinar service on top, and you will cross ten. When that happens, the cheapest fix is almost always deletion — audit the list and remove the providers that no longer send. The second cheapest is moving bulk mail to a subdomain such as mail.example.com or news.example.com, which gets its own SPF record and its own fresh budget of ten while keeping the parent domain clean.
~all or -all?
~all (SoftFail) says "this sender is probably not authorised, accept the message but note it". -all (Fail) says "this sender is not authorised, you may reject it". In the DMARC era the difference is smaller than it used to be: if you publish p=quarantine or p=reject, a DMARC-failing message is acted on regardless of whether SPF said SoftFail or Fail. The reason to start with ~all is operational, not technical — you almost certainly have a sender you have forgotten, and SoftFail gives you a month of aggregate reports to find it without losing mail.
Move to -all once your DMARC reports show only known sources. A domain that never sends mail at all should publish v=spf1 -all immediately — that is the correct, complete record for a parked or web-only domain, and it costs zero lookups.
Publishing it correctly
- Create a TXT record — not an SPF (type 99) record. That record type was deprecated in 2014 and receivers no longer query it.
- Set the name/host to
@or the bare domain. SPF onspf.example.comdoes nothing; that name only ever exists as an include target. - Paste the value exactly, on one line, without wrapping quotes unless your panel requires them.
- Delete any other
v=spf1record on the same name. Two SPF records is an instant PermError. - Wait for the old TTL to expire, then verify with the SPF checker and a raw TXT lookup.
If the record is longer than 255 characters it must be published as several quoted strings inside a single TXT record; they concatenate with no separator. Most DNS panels handle the split automatically. A few insert a space between chunks, which corrupts the record — verify with dig after publishing, not just in the panel UI.
Verify from the command line
# Confirm exactly one v=spf1 record exists on the bare domain
dig +short TXT example.com | grep spf1
# See the TTL so you know when a change will be live everywhere
dig TXT example.com +noall +answer
# Inspect a provider include before you add it
dig +short TXT spf.protection.outlook.com
# Bypass your local resolver cache
dig @1.1.1.1 +short TXT example.comThen do the other two records
SPF alone does not stop anyone putting your domain in a From: header, and it breaks whenever a recipient forwards your mail. Pair it with a DKIM signature — check yours with the DKIM checker — and a DMARC policy built with the DMARC generator. SPF plus DKIM plus DMARC is the set Google and Yahoo require from bulk senders; any one of them on its own is not enough.