Skip to content
Pidgely
  • deliverability
  • authentication
  • dns

SPF, DKIM and DMARC Explained: Setup and Alignment Guide

How SPF, DKIM and DMARC work together, how alignment really works, and a step-by-step setup with DNS records you can copy and adapt.

Pidgely teamPublished 6 min readMarkdown version

On this page
  1. How each protocol works
  2. Alignment, the part most people get wrong
  3. Step-by-step setup
  4. Verifying in a real message
  5. Common mistakes
  6. Checklist
  7. Frequently asked questions

SPF, DKIM and DMARC are three DNS-published standards that let a receiving mail server verify that a message really comes from the domain it claims. SPF (RFC 7208) lists the servers allowed to send for a domain, DKIM (RFC 6376) attaches a cryptographic signature to each message, and DMARC (RFC 7489) ties both back to the visible From address through a rule called alignment and tells receivers what to do when checks fail. You need all three: Google's and Yahoo's sender guidelines require them for bulk senders since February 2024.

How each protocol works

SPF: who may send for this domain

SPF checks the envelope sender (the MAIL FROM address in the SMTP transaction, later visible as the Return-Path header), not the From header the user sees. The receiver looks up a TXT record on that domain and checks whether the connecting IP is authorized.

DNS
bounces.example.com.  IN TXT  "v=spf1 ip4:203.0.113.0/24 include:_spf.example.net -all"

Key details from RFC 7208:

  • Only one SPF record per name. Two v=spf1 records produce a permerror.
  • Evaluation may perform at most 10 DNS lookups (include, a, mx, ptr, exists, redirect). Nested includes count too.
  • -all (fail) and ~all (softfail) both matter less than you think once DMARC is enforced: DMARC only cares whether SPF passed and aligned.

SPF's weakness is forwarding. When a mailing list or a .forward rule relays your message, the forwarder's IP is not in your record, so SPF fails at the final hop.

DKIM: a signature that travels with the message

DKIM signs selected headers and the body with a private key. The signature goes into a DKIM-Signature header, and the public key lives in DNS under <selector>._domainkey.<domain>.

text
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
 s=s2026; h=from:to:subject:date:message-id:list-unsubscribe;
 bh=...; b=...
DNS
s2026._domainkey.example.com.  IN TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqh..."

The d= tag is the signing domain, and it is what DMARC compares against the From header. Use RSA keys of at least 2048 bits (RFC 8301 deprecates keys under 1024 bits and rsa-sha1), and rotate them periodically by publishing a new selector before switching to it. Because the signature is attached to the content, DKIM generally survives plain forwarding, unless an intermediary modifies the signed headers or body (mailing lists that add footers are the classic case).

DMARC: alignment and policy

DMARC is published at _dmarc.<domain>:

DNS
_dmarc.example.com.  IN TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; adkim=r; aspf=r; pct=100"

A message passes DMARC if at least one of these is true:

  1. SPF passed and the MAIL FROM domain aligns with the From domain.
  2. DKIM passed and a valid signature's d= domain aligns with the From domain.

The p= tag sets the policy for failing messages: none (monitor only), quarantine (usually spam folder) or reject. The rua= tag receives daily aggregate XML reports from receivers, which is how you discover every system sending as your domain.

Alignment, the part most people get wrong

Alignment is the reason a message can "pass SPF" and "pass DKIM" yet still fail DMARC. Consider a message sent through a provider that uses its own domains:

text
From: Billing <billing@example.com>
Return-Path: <bounce-8f2a@mail.example.net>
DKIM-Signature: ... d=example.net ...

SPF passes for example.net and DKIM passes for example.net, but neither matches example.com, so DMARC fails. The fix is to make both identifiers use your domain:

text
From: Billing <billing@example.com>
Return-Path: <bounce-8f2a@bounces.example.com>
DKIM-Signature: ... d=example.com ...

With relaxed alignment (adkim=r, aspf=r, the default), the organizational domains only need to match, so bounces.example.com aligns with example.com. With strict alignment (s), the domains must match exactly. Relaxed is the right choice for almost everyone, because it lets you use a dedicated return-path subdomain.

Step-by-step setup

1. Inventory every sender

List everything that sends as your domain: your application, your marketing tool, your helpdesk, your CRM, Google Workspace or Microsoft 365. Each one needs aligned SPF or aligned DKIM, ideally both.

2. Set up a custom return-path subdomain

Create a subdomain such as bounces.example.com for the envelope sender. Point its MX at the server that processes bounces and publish an SPF record that authorizes your sending IPs:

DNS
bounces.example.com.  IN MX   10 mx.example.com.
bounces.example.com.  IN TXT  "v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 -all"

Using a subdomain keeps your root SPF record short and avoids hitting the 10-lookup limit.

3. Publish DKIM keys per domain

Generate a 2048-bit key pair per sending domain, publish the public key under a selector, and configure your MTA to sign with d=example.com. Verify with:

bash
dig +short TXT s2026._domainkey.example.com

4. Publish DMARC in monitoring mode

Start with p=none and a reporting address. Leave it for at least a few weeks and read the aggregate reports (any DMARC report parser will turn the XML into something readable).

5. Fix every legitimate failing source

For each source that fails alignment, either configure custom DKIM signing with your domain or move it to an aligned return-path. Unknown sources that fail are often spoofing attempts, which is exactly what enforcement will stop.

6. Move to enforcement gradually

Progress to p=quarantine, optionally with pct= to apply it to a fraction of failing mail, then to p=reject. Add sp= if you want a different policy for subdomains.

DNS
_dmarc.example.com.  IN TXT  "v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com; adkim=r; aspf=r"

Verifying in a real message

Send a test to a Gmail or Outlook mailbox and open the raw source. Look for the Authentication-Results header (RFC 8601):

text
Authentication-Results: mx.google.com;
       dkim=pass header.i=@example.com header.s=s2026;
       spf=pass (google.com: domain of bounce-8f2a@bounces.example.com designates 203.0.113.10 as permitted sender) smtp.mailfrom=bounces.example.com;
       dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com

All three should read pass, and header.from, smtp.mailfrom and header.i should share the same organizational domain.

Common mistakes

  • Two SPF records on the same name, usually after adding a new vendor. Merge them into one.
  • Exceeding 10 DNS lookups by stacking include: entries. Move sending to a subdomain or replace includes with explicit ip4:/ip6: ranges you control.
  • DKIM signed with the vendor's domain instead of yours. It passes DKIM but not DMARC.
  • Jumping straight to p=reject before reading reports, which silently blocks a forgotten system such as invoicing.
  • Forgetting subdomains. Without sp=, subdomains inherit the parent policy; attackers often target random.example.com.
  • Never rotating DKIM keys, or deleting the old selector before mail signed with it has been delivered.
  • Line-length issues in DNS. A 2048-bit key exceeds 255 characters and must be split into multiple quoted strings in one TXT record; some DNS panels do this for you, others break it.

Checklist

  • [ ] One SPF record per sending name, under 10 lookups
  • [ ] Custom return-path subdomain that aligns with the From domain
  • [ ] 2048-bit DKIM key with d= set to your domain
  • [ ] DMARC record with rua= reporting
  • [ ] All legitimate sources passing aligned in aggregate reports
  • [ ] Policy moved to quarantine, then reject
  • [ ] DKIM key rotation scheduled

Pidgely configures this for you by design: each domain gets its own DKIM key, and the envelope sender uses a custom return-path subdomain so SPF aligns with your From domain. You still own the DNS records, and the dashboard shows which ones are verified.

Frequently asked questions

What is the difference between SPF, DKIM and DMARC?

SPF authorizes which IP addresses may send for the envelope sender domain, DKIM adds a cryptographic signature tied to a domain, and DMARC tells receivers what to do when neither of them passes in alignment with the visible From domain.

What does DMARC alignment mean?

Alignment means the domain that passed SPF (the Return-Path domain) or DKIM (the d= domain) matches the domain in the From header. With relaxed alignment, a subdomain such as bounces.example.com aligns with example.com.

Do I need both SPF and DKIM for DMARC to pass?

No. DMARC passes if either SPF or DKIM passes and is aligned. In practice you should configure both, because SPF breaks on forwarding while DKIM usually survives it.

Should I start DMARC with p=reject?

No. Start with p=none and a rua reporting address, review aggregate reports until all legitimate sources pass aligned, then move to quarantine and finally reject.

How many DNS lookups can an SPF record use?

RFC 7208 limits SPF evaluation to 10 DNS-querying mechanisms and modifiers (include, a, mx, ptr, exists, redirect). Exceeding it produces a permerror, which receivers treat as a failure.

Pidgely team

Published

We build Pidgely, the email API that gets you to the inbox. We write about what we learn delivering email, citing the standards and mailbox provider guidelines behind every claim.

Also available in:
deliverabilitytroubleshooting

Why Your Emails Go to Spam: A Troubleshooting Guide

Find out why your emails land in spam: a step-by-step guide to authentication, reputation, list quality, content and infrastructure, with checks to run today.

5 min read