How to build an SPF record that actually works
SPF — Sender Policy Framework — is the simplest of the three email authentication records (SPF, DKIM and DMARC), and the one most often broken by a small mistake. It is a single line of text in your DNS that answers one question for every receiving mail server: which servers are allowed to send email using your domain name? Get it wrong and your mail lands in spam, or is rejected outright, with no warning to you.
What is an SPF record?
An SPF record is a TXT record published at the root of your domain. When a message arrives claiming to be from you, the receiving server looks up your SPF record and checks whether the server that actually sent the message is on the list. If it is, SPF passes. If it is not, the result depends on your ending policy: a soft fail (~all) means the message is accepted but treated as suspicious; a hard fail (-all) means it should be rejected. SPF only checks the envelope sender — the return-path address bounces go to — not the From address your recipients see, which is why it works best together with DKIM and DMARC. Without one, anyone can send mail claiming to be from your domain.
The parts of an SPF record
Every record starts with v=spf1 and ends with a single all mechanism. In between are the mechanisms that list your senders, each optionally starting with a qualifier: + (pass, the default), - (fail), ~ (soft fail) or ? (neutral).
include:— pulls in another domain's SPF record. This is how you authorize a provider:include:_spf.google.comfor Google Workspace,include:spf.protection.outlook.comfor Microsoft 365,include:sendgrid.netfor SendGrid. Each include costs at least one DNS lookup.mx— authorizes the servers in your domain's MX records, i.e. your incoming mail servers. Useful when the same servers also send your mail.a— authorizes the servers in your domain's A record, usually your web server. Only add it if that server actually sends mail.ip4:andip6:— authorize one address or a whole range, likeip4:203.0.113.10orip4:203.0.113.0/24. These cost no DNS lookups, which makes them the cheapest way to list a server you control.all— the catch-all at the end.~allsoft-fails everything unlisted;-allrejects it;?allhas no opinion. Never use+all: it allows every server on the internet to send as your domain, which defeats the entire point of SPF.
Two mechanisms in older guides are best avoided: ptr is deprecated — slow, because receivers must do a reverse DNS lookup for every sender, and some ignore it entirely — and exists: is rarely needed outside specialist setups.
The 10 DNS lookup limit
RFC 7208, the standard that defines SPF, caps evaluation at 10 DNS lookups per check. Every include:, a, mx, exists: and redirect costs one — and the lookups inside an included record count too. Google Workspace's include:_spf.google.com pulls in three more records, so one include costs four of your ten. Cross the limit and receivers return a permanent error, which means SPF fails exactly as if you had no record at all — silently, with no bounce to warn you. This is the most common way SPF breaks in practice. The counter in the builder above tracks your total as you work and warns you from eight lookups onward. If you are over the limit, replace some includes with ip4: addresses, which cost nothing, or drop a sender you no longer use.
Worked example
Take a small business that sends mail from its own mail server, one application server, Google Workspace and SendGrid:
v=spf1 mx ip4:203.0.113.10 include:_spf.google.com include:sendgrid.net ~all
Read left to right: v=spf1 marks this as an SPF record. mx authorizes the mail servers in the domain's MX records. ip4:203.0.113.10 authorizes the application server. include:_spf.google.com pulls in Google Workspace's record (4 lookups: the include plus 3 inside it). include:sendgrid.net pulls in SendGrid's record (1 lookup). ~all soft-fails everything else. Total: 6 lookups out of 10 — comfortably inside the limit, with room for one more provider.
~all or -all: which ending should you choose?
Start with ~all. A soft fail tells receivers to accept mail from unlisted servers but treat it as suspicious, which protects you while you are still finding every system that sends as your domain — the helpdesk, the CRM, the invoicing tool, the old server someone forgot about. Switch to -all only after a few weeks of normal sending with nothing missing, because a hard fail means one forgotten sender has its mail rejected with no warning. ?all (neutral) is the weakest option: it tells receivers you have no opinion about unlisted senders.
Common mistakes that break SPF
Too many DNS lookups
Each include costs at least one lookup, and providers' records add more inside. Eleven lookups means a permanent error and SPF failing silently. Count before you publish — the builder above does it live.
Two SPF records
A domain may have exactly one TXT record starting with v=spf1. Two records invalidate both. Merge every provider into one line instead of adding a second record per provider.
A forgotten sender
The helpdesk, the CRM, the transactional mailer — any sender you miss fails SPF. List every system that sends as your domain before switching to -all.
+all, or no ending at all
+all allows the whole internet to send as your domain. A record with no ending policy leaves receivers guessing. Always end with ~all or -all.
Publishing in the wrong place
The record goes on the root of your domain (host @), not on a subdomain — unless that subdomain sends its own mail separately. A record on the wrong host simply never gets checked.
Changing it and expecting instant results
DNS changes usually appear within an hour but can take up to 48 hours to reach every receiver. If mail still fails SPF right after publishing, wait before editing the record again.
How to publish the record
Copy the record from the builder, sign in to your DNS provider, and create a TXT record with Name or Host set to @ and Value set to the full record, starting with v=spf1. Leave TTL at 3600 or Auto. Then paste your published record into the checker above to confirm the syntax — and if you already had an SPF record, edit it rather than creating a second one.