Skip to content

SPF Record Generator

An SPF record generator builds the single v=spf1 TXT record that lists every server allowed to send mail for your domain. Pick your providers, add any of your own sending IPs, choose a softfail or hardfail ending, and publish the result as one TXT record on the bare domain.

Which services send mail as your domain?

ip4: and ip6: terms cost zero DNS lookups, so use them for your own servers instead of a or mx when the addresses are stable.

What should happen to mail from anyone else?
Your SPF record
v=spf1 include:_spf.google.com ~all
Lookup-consuming terms here
1 / 10
Record length
35
Publish as
TXT at @ (root)

That figure counts only the terms in this record. Each include: pulls in the provider’s own record, which spends more of the same 10-lookup budget — sometimes three or four. Publish this, then run the SPF checker to see the real recursive total.

How to publish it
  1. In your DNS panel add a TXT record.
  2. Name/host: @ (or the bare domain — never spf or _spf).
  3. Value: the record above, exactly as shown.
  4. Delete any other v=spf1 TXT record on the same name. Two SPF records is a PermError.

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 ~all
One TXT record on the bare domain. Nothing else is required.

The 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

TermAuthorisesDNS lookups
ip4:203.0.113.0/24An IPv4 address or CIDR range0
ip6:2001:db8::/32An IPv6 address or CIDR range0
include:_spf.google.comEverything in another domain's SPF record1 + whatever that record itself spends
aThe A/AAAA addresses of this domain1
mxThe addresses of this domain's MX hosts1 (plus up to 10 address lookups)
ptrHosts whose reverse DNS matches — deprecated1, and receivers may ignore it
exists:%{i}._spf.example.comMacro-expanded existence test1
~all / -allEveryone else0
Read the full explanation of spf record generator results ↓

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.

Never add 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

  1. Create a TXT record — not an SPF (type 99) record. That record type was deprecated in 2014 and receivers no longer query it.
  2. Set the name/host to @ or the bare domain. SPF on spf.example.com does nothing; that name only ever exists as an include target.
  3. Paste the value exactly, on one line, without wrapping quotes unless your panel requires them.
  4. Delete any other v=spf1 record on the same name. Two SPF records is an instant PermError.
  5. 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.com
If grep returns two lines, you have two SPF records and SPF is already broken.

Then 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.

SPF Checker
Validate SPF syntax and count the 10-lookup limit live

Frequently asked questions

Where exactly do I publish the SPF record?
As a TXT record on the bare domain — host @ in most panels. Not on spf., not on _spf., and not as a legacy type-99 SPF record. If you send from a subdomain such as mail.example.com, that subdomain needs its own separate TXT record; SPF is never inherited.
Can I combine Google Workspace and Microsoft 365 in one record?
Yes — v=spf1 include:_spf.google.com include:spf.protection.outlook.com ~all is valid and common during a migration. Watch the lookup count: those two includes together already spend a meaningful share of the ten, so remove the one you are leaving as soon as the cutover is complete.
Do I need to list my website server if it sends contact-form mail?
Only if the form sends with an envelope sender at your domain. If PHP mail() or a framework sends from the web server directly, add that server IP as an ip4: term. The better fix is to route those messages through your normal SMTP provider so the existing include already covers them.
What does a domain that never sends email need?
Publish v=spf1 -all on the bare domain, and pair it with a DMARC record of v=DMARC1; p=reject;. That combination tells every receiver that no mail should ever claim to come from the domain, and it costs zero DNS lookups.
Is +all ever appropriate?
No. +all passes SPF for every host on the internet, which makes the record actively harmful — it launders spoofed mail through your domain and can push a DMARC evaluation to pass on forged messages. If a vendor asks you to publish it, the vendor is wrong.
My provider gave me a record with redirect= instead of include:. Is that fine?
redirect= replaces your record entirely with the target domain's record, so nothing else in yours is evaluated and your own all never applies. It suits a domain that sends only through that one provider. If you also send from anywhere else, use include: instead — and note that redirect= is ignored outright when an all mechanism is present.
How long until the new record takes effect?
As long as the TTL on the previous TXT record, because resolvers that already cached the old answer keep serving it until it expires. Lower the TTL to 300 seconds a day before a planned change, make the change, then restore it. Publishing a fix does not flush caches that are already holding the broken record.