Why Your Mail Gets Rejected
You send an invoice. The client never sees it. You check your mail logs and find a terse SMTP rejection: 550 5.7.1 Domain not authenticated. The receiving MTA decided your message looked like a forgery and dropped it on the floor.
This happens because modern mail receivers — Gmail, Microsoft 365, Yahoo, and most corporate mail gateways — enforce a three-layer authentication stack: SPF, DKIM, and DMARC. If any layer is missing or misconfigured, your mail gets quarantined or bounced. Setting all three up correctly is not optional anymore; it is table stakes for deliverability.
This article walks through each protocol, what problem it solves, and the exact DNS records and commands you need to get it right. We will also cover the tools on this site that automate the tedious parts — the Email Authentication Checker, the SPF Flattener, and the SPF/DMARC Record Generator.
SPF: Who Can Send Mail As Your Domain
Sender Policy Framework (SPF) is a DNS TXT record that lists every server authorized to send mail on behalf of your domain. When a receiving MTA sees a message claiming to be from @example.com, it looks up the SPF record for example.com, checks if the connecting IP is in the list, and passes or fails accordingly.
A minimal SPF record looks like this:
example.com. IN TXT "v=spf1 mx -all"
This says: allow the IPs listed in the domain's MX records, and hard-fail everything else. The -all qualifier tells receivers to reject anything not explicitly permitted. For a domain that sends mail only through its own mail servers, this is often sufficient.
Most organizations need a longer list. You might send through Google Workspace, a transactional mail service like SendGrid, your CRM, and an internal mail relay. A realistic SPF record expands quickly:
v=spf1 include:_spf.google.com include:sendgrid.net include:spf.protection.outlook.com ip4:198.51.100.0/24 mx -all
Each include pulls in another domain's SPF record, and each of those can pull in more. This is where the most common SPF configuration error originates: the 10-DNS-lookup limit.
The 10-Lookup Limit
RFC 7208, Section 4.6.4 specifies that SPF evaluators must not perform more than 10 DNS lookups per evaluation. This includes include, a, mx, ptr, and exists mechanisms. If your record triggers more than 10 lookups, the result is a PermError — the entire SPF check is voided, and receivers treat it as if no SPF record exists at all.
You can check your current lookup count with a quick dig:
dig txt example.com | grep spf
Then paste it into the Email Authentication Checker on this site, which counts your lookups and flags each one. If you are at 8 or 9, you are one vendor addition away from breakage. If you are over 10, your SPF is already broken.
Fixing SPF with Flattening
Flattening resolves all include and a/mx mechanisms into raw ip4 and ip6 addresses at record-generation time. The resulting record contains no includes and therefore consumes exactly 1 DNS lookup. The tradeoff is maintenance: when Google or SendGrid adds new IPs, your flattened record does not automatically pick them up. You must regenerate periodically.
The SPF Flattener does this automatically. Feed it your current SPF record, and it resolves every mechanism to its underlying address range, producing a flat record you can deploy immediately. You should re-run it monthly or tie it into a CI job that alerts you when the flattened output diverges from a fresh resolution.
You can also use the SPF/DMARC Record Generator to build a properly structured record from scratch, choosing your senders from a list instead of hand-editing TXT strings.
Common SPF Pitfalls
One record per domain. If you have two SPF TXT records, the result is undefined and most receivers fail the check. Merge everything into a single record.
Do not use +all. Ever. It authorizes the entire internet to send as your domain.
Do not use ptr. It is deprecated in RFC 7208 and triggers arbitrary reverse DNS lookups that are slow, unreliable, and count against your lookup budget.
Subdomains do not inherit the parent's SPF unless you explicitly publish an SPF record on the subdomain or use a wildcard record. If you send mail from mail.example.com but only have SPF on example.com, those messages fail.
DKIM: Cryptographic Proof of Authenticity
SPF checks the envelope sender's IP. DKIM checks the message body and headers against a cryptographic signature. Even if an attacker spoofs the envelope, they cannot produce a valid DKIM signature without the private key.
DKIM works by publishing a public key in DNS and signing outbound messages with the corresponding private key. The receiving MTA fetches the public key and verifies the signature against the message. If it matches, the message passes DKIM.
Generating DKIM Keys
Most mail providers generate keys for you and give you the DNS record to publish. If you run your own MTA (Postfix, Exim, OpenSMTPD), you generate the keypair yourself:
openssl genrsa -out dkim_private.pem 2048
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem
The public key goes into a DNS TXT record under a selector you choose. Selectors let you rotate keys: you can have 202606._domainkey.example.com and 202612._domainkey.example.com active simultaneously, then retire the old one after a grace period.
A typical DKIM DNS record looks like:
202606._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC..."
The p= value is the Base64-encoded public key with whitespace and PEM headers stripped. You can extract it with:
openssl rsa -in dkim_public.pem -pubin -outform der 2>/dev/null | openssl base64 -A
Canonicalization and Header Selection
DKIM signs specific headers. If an intermediary adds a header after signing, a strict check fails. Most configurations use relaxed/simple canonicalization: relaxed for headers (case-insensitive, whitespace-normalized), simple for the body (no modification tolerated).
The minimum headers to sign are From and Date. Adding Subject, To, CC, Reply-To, and Message-ID improves security. Signing List-Unsubscribe prevents attackers from injecting unsubscribe headers into your mail stream.
Key Rotation and DNS Propagation
DNS changes take time to propagate. When rotating DKIM keys, publish the new selector's public key, wait at least 48 hours, then switch your MTA to sign with the new key. Keep the old key in DNS for another week so in-flight messages can still be verified. After that, remove the old record.
Use 2048-bit RSA keys. 1024-bit keys are factorable by anyone with moderate compute resources and are considered broken for DKIM since 2022. Some receivers reject 1024-bit DKIM signatures outright.
DMARC: Tying SPF and DKIM Together
DMARC (Domain-based Message Authentication, Reporting, and Conformance) adds a policy layer on top of SPF and DKIM. It tells receivers what to do when authentication fails and where to send reports about those failures.
A DMARC record is another DNS TXT record, published at _dmarc.example.com:
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; ruf=mailto:forensic@example.com; pct=100; adkim=r; aspf=r"
Let us break this down:
- p= — The policy. Start with
p=none(report-only, no action). After reviewing reports and confirming legitimate mail passes, move top=quarantine(send failures to spam). The final state isp=reject(bounce failures outright). - rua= — Where aggregate XML reports are sent. These are daily summaries from participating receivers showing pass/fail rates per sending IP.
- ruf= — Where forensic (failure) reports are sent. These include redacted copies of failed messages. Most large receivers do not send forensic reports for privacy reasons.
- pct= — Percentage of failing mail the policy applies to. Useful during rollout: set
pct=10to quarantine only 10% of failures while you verify nothing breaks. - adkim= and aspf= — Alignment mode.
r(relaxed) means the domain in the DKIM signature or SPF return-path must share an organizational domain with the From header.s(strict) requires an exact match. Relaxed is almost always correct.
Alignment: The Critical Concept
For DMARC to pass, the message must pass SPF or DKIM, and the domain used in the passing authentication must align with the domain in the From: header. This is what stops subdomain spoofing.
If your SPF return-path is bounce.sg-bounces.example.com (relaxed alignment matches on example.com) but your From header is @example.com, relaxed alignment passes. If your From header is @sub.example.com, relaxed alignment still passes because example.com is the organizational domain for both. Strict alignment would require an exact match and would fail in both cases.
Misalignment is why many domains with valid SPF and DKIM still fail DMARC. Their transactional mail provider uses a different domain in the return-path or DKIM signature, and the receiving MTA sees two different domains and applies the DMARC policy.
Using the DMARC Record Generator
Hand-building DMARC records leads to typos and syntax errors that silently invalidate the entire record. Use the SPF/DMARC Record Generator to produce a syntactically correct record with all the right tags. Choose your policy, add your report addresses, pick alignment modes, and copy the output directly into your DNS zone.
Testing Your Setup
After publishing all three records, verify them before depending on them in production. Start with a DNS query to confirm they are visible:
dig txt example.com +short | grep spf
dig txt 202606._domainkey.example.com +short
dig txt _dmarc.example.com +short
Then run the Email Authentication Checker against your domain. It performs a full SPF/DKIM/DMARC validation, counts DNS lookups, checks key lengths, verifies alignment, and flags anything that would cause a receiver to reject your mail.
For a live test, send a message to a mailbox you control at Gmail or Outlook, then view the original headers. Gmail shows authentication results in the Authentication-Results header:
Authentication-Results: mx.google.com;
spf=pass smtp.mailfrom=example.com;
dkim=pass header.i=@example.com;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=example.com
All three should show pass. If anything shows fail, softfail, neutral, or none, go back and fix the corresponding record.
Maintenance and Monitoring
Email authentication is not set-and-forget. Services change IPs, keys expire, and vendors get acquired. Your monitoring checklist:
- Monthly: Re-run the SPF Flattener if you use flattened records. Check for new IP ranges from your senders.
- Quarterly: Review DMARC aggregate reports. Look for unknown sending sources — they indicate shadow IT or a compromised account sending mail without your knowledge.
- Annually: Rotate DKIM keys. Generate a new keypair, publish the new selector, wait, switch signing, wait, remove old selector.
- On vendor change: Update SPF includes immediately. A decommissioned vendor's SPF include may disappear from DNS, and if your record references a nonexistent domain, SPF evaluation can produce unexpected results.
With SPF, DKIM, and DMARC properly configured, your mail lands in inboxes instead of spam folders. Your domain stops being trivially forgeable. And when something does go wrong — because something always goes wrong — the DMARC reports tell you exactly what failed and from which IP.
Quick Reference
| Protocol | DNS Record Location | Purpose |
|---|---|---|
| SPF | example.com TXT | Authorize sending IPs |
| DKIM | selector._domainkey.example.com TXT | Cryptographic signature verification |
| DMARC | _dmarc.example.com TXT | Policy and reporting for SPF+DKIM |
Run the Email Authentication Checker against your domain now. You might find a problem you did not know you had.