Cart
Net 9 regions NRT 232 ms SYD 264 ms AMS 12 ms Uptime 30d 99.997 %
All posts

Guides

SPF, DKIM, DMARC without breaking your email

Omega Digital 8 min read

Email authentication is one of those things every hosting customer needs, almost nobody explains well, and a lot of tutorials get subtly wrong. This is the version we wish we had when we started: what each record does, the specific ways people break them, and the order we recommend rolling them out.

Contents

  • · Why email needs three records, not one
  • · SPF: who is allowed to send as you
  • · DKIM: cryptographic proof the message is really from you
  • · DMARC: the policy that ties SPF and DKIM together
  • · The rollout order we recommend
  • · Common ways people break this

SPF, DKIM, and DMARC are three different records doing three different jobs. They are sometimes presented as a single block of copy-paste DNS to tack onto a domain, which is how people end up with email that silently fails to deliver. We will go through each one, what it does, the common failure modes, and the order we deploy them in for customers.

A note on examples: the sending-host values below (`omega-mail.omdigital.cc`) are placeholders. Replace them with whatever host actually sends mail for your domain: your Microsoft 365 tenant, Google Workspace, SendGrid, your own MTA, or whatever mix of the above you end up with.

Why email needs three records, not one

Email authentication answers three separate questions. SPF answers "is the sending server on your allow-list?" DKIM answers "was the message signed with a key you publish?" DMARC answers "what should the receiver do if SPF or DKIM fails, and where should they tell you about it?"

You need all three because none is sufficient alone. SPF breaks when mail is forwarded (the forwarder is not on your allow-list). DKIM signatures survive forwarding but do not themselves say anything about policy. DMARC is the layer that lets you say "if both SPF and DKIM fail alignment, quarantine the message and email me the report". Critically, it is the only part that produces reports you can actually read.

SPF: who is allowed to send as you

SPF is a single TXT record at the apex of your domain. It lists the hosts, IP ranges, and include-references that are authorized to send mail with your domain in the envelope-from (the address in `MAIL FROM`, not the `From:` header).

dns
example.com.  IN  TXT  "v=spf1 include:omega-mail.omdigital.cc include:_spf.google.com ip4:203.0.113.10 ~all"

Walkthrough: `v=spf1` is the version. `include:omega-mail.omdigital.cc` delegates to our mail platform's SPF record (replace with your actual sending provider). `include:_spf.google.com` covers Google Workspace if you also use it. `ip4:203.0.113.10` is a specific IP; add this for one-off senders like a marketing automation server. `~all` means "anything else is a softfail, probably not legitimate", the safer choice during rollout than `-all` (hardfail).

Three specific traps with SPF:

  • · The 10-lookup limit. SPF limits a single evaluation to 10 DNS lookups. Each `include:` and each `a:` counts. Stack enough provider includes and you blow past 10, at which point the record is treated as `permerror` and effectively disabled. Check with an SPF analyzer before you deploy.
  • · `~all` vs `-all`. Start with `~all`. It lets receivers note the failure but still deliver (usually to spam). Move to `-all` only after a clean DMARC reporting period with no legitimate sources failing.
  • · Only one SPF record per domain. Multiple `v=spf1` TXT records on the same name is a `permerror`. If you need to combine sources, combine them into one record with multiple `include:` entries.

DKIM: cryptographic proof the message is really from you

DKIM (DomainKeys Identified Mail) works by having your sending server sign each outgoing message with a private key, and publishing the matching public key in DNS. Receivers fetch the public key and verify the signature. If it verifies, they know the message was signed by whoever holds the private key and that the signed body and headers have not been modified in transit.

You publish a DKIM public key under a selector, a label that lets you rotate keys without replacing them in place. The DNS name is `<selector>._domainkey.<domain>`.

dns
od2026._domainkey.example.com.  IN  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0x7...key-continues...AB"

Two things that trip people up:

  • · Key length. Use 2048-bit RSA. 1024-bit still works at most receivers but Google and some others flag it. 4096-bit is technically stronger but some older receivers fail to validate it.
  • · TXT chunking. A DKIM public key is long, often 400+ characters. A single TXT record "string" in DNS can only be 255 characters. Longer values must be split into multiple quoted strings within the same record, which the resolver concatenates. Most managed DNS UIs handle this for you. If yours does not, the record will save but fail to validate.

You can verify DKIM is resolving correctly from the command line:

bash
# Fetch the DKIM record for a given selector
dig +short TXT od2026._domainkey.example.com

# Send a test email and check the Authentication-Results header
# at the receiving end — it should contain 'dkim=pass'

DMARC: the policy that ties SPF and DKIM together

DMARC is published as a TXT record at `_dmarc.<domain>`. It tells receivers two things: what to do with mail that fails SPF-or-DKIM alignment with your domain, and where to send aggregate reports so you can see what is actually happening.

dns
_dmarc.example.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; adkim=r; aspf=r; pct=100"

`p=none` is "do nothing, but report". `p=quarantine` is "send failures to spam". `p=reject` is "bounce failures outright". `rua=` is the address for aggregate reports: you will get one XML bundle per receiving domain per day, summarizing which IPs sent mail claiming to be you and whether they passed authentication.

`adkim=r` and `aspf=r` set alignment to relaxed: the From-header domain has to match the SPF or DKIM domain at the organizational level, but a subdomain is fine. Strict alignment (`s`) requires an exact match and is unforgiving in practice.

The rollout order we recommend

Do not publish `p=reject` on day one. We have watched customers do it, lose a week of legitimate transactional mail that was being sent from a forgotten mailing list service, and have to explain to their users why the password reset emails stopped working. The sequence that works:

  • · Day 1: Publish SPF with `~all` and DKIM for your primary sending provider. Verify with a test message to a Gmail address: check the Authentication-Results header shows `spf=pass` and `dkim=pass`.
  • · Day 1 also: Publish DMARC with `p=none` and a working `rua=` address. Pick a reports mailbox you actually check.
  • · Days 1–14: Read the aggregate reports. You will discover senders you forgot about: an old newsletter service, a WordPress contact form sending via SMTP, a third-party invoicing tool. Add each legitimate source to SPF and enable DKIM for it if the provider supports it.
  • · Day 14: When reports show only legitimate sources and they are all passing, move DMARC to `p=quarantine; pct=25`. The `pct=` lets you stage enforcement: 25% of failing mail is quarantined, the rest still delivers.
  • · Day 21: Ramp `pct=` to 100 if quarantine looks clean.
  • · Day 28 or later: Move to `p=reject` only if you are confident. Some organizations stay at `p=quarantine` indefinitely and that is a defensible choice.

Common ways people break this

  • · Jumping straight to `p=reject` without a reporting period. You will lose mail you did not know you were sending.
  • · Adding a new sending service and forgetting to update SPF. Transactional mail from the new service goes to spam, nobody notices for weeks.
  • · Putting the DKIM key in the wrong TXT record name. It must be `<selector>._domainkey.<domain>`, not `<selector>.<domain>` or `_domainkey.<selector>.<domain>`.
  • · Copy-pasting a DMARC record with an `rua=` address nobody reads. You will miss the signal that tells you the rollout is working.
  • · Multiple SPF records on the same name. This fails open: receivers treat it as permerror and skip SPF entirely.
  • · Relying on SPF alone for a forwarded-heavy setup (mailing lists, aliases). Forwards almost always break SPF; DKIM is what survives.

If you want the short version: publish all three, start relaxed, read the reports for two weeks, and only then tighten. The tools that analyze DMARC reports (there are several free ones) turn the XML into a readable dashboard, which makes the reporting period a lot less painful.

Email authentication is a reporting exercise first and an enforcement exercise second. Skip the reporting and you are tightening policy on a system you do not understand.
OD

Omega Digital

Platform · Omega Digital