"Our emails are going to spam" - a sysadmin's triage order
The three causes
- Authentication - SPF, DKIM and DMARC. Binary, free to check, fixable in an afternoon. Either the receiver can verify you sent the message or it can't.
- Reputation - what your sending IP and domain have done lately. Slow to fix, measurable.
- Content and engagement - what's in the message and whether anyone wants it. The vaguest, the most over-blamed, and the last thing you should look at.
Cause 1 is the one you can settle in ten minutes with dig. Start there.
Step 0: get an actual failing message
Before touching DNS, get the full headers of one message that landed in spam. Not a screenshot, not a forward - a forward re-signs and rewrites everything you need to read. Ask for "show original" (Gmail) or "view message source" (Outlook) and have them paste the text. You want this header:
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=selector1;
spf=pass (google.com: domain of b*****@mail.example.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=b*****@mail.example.com;
dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=example.com
Read it carefully, because this exact shape is the single most common deliverability bug and it looks like success at a glance. SPF passed. DKIM passed. DMARC failed. That's not a contradiction - it's an alignment failure, and I'll come back to it.
If you can't get a real message, the DMARC checker will read all three records for a domain from DNS and tell you what's published, which is enough to start.
Cause 1: authentication
SPF
$ dig +short TXT example.com | grep spf1
"v=spf1 include:_spf.google.com include:sendgrid.net ~all"
Two failure modes matter, and neither is visible by eyeballing the record.
- More than ten DNS lookups. RFC 7208 ยง4.6.4 caps evaluation at 10 DNS-querying mechanisms -
include,a,mx,ptr,exists,redirect- counted recursively through everyinclude. Your record can be two lines long and still blow the limit, because a single vendor'sincludecan spend five on its own. Over the limit, receivers returnpermerror, and most treat that as an outright failure. This is the classic slow-motion outage: someone adds one more SaaS vendor, the record tips from 10 to 11, and mail that authenticated for years quietly stops. Nothing in your monitoring fires. I cleaned up a domain last week that was at 7 of 10 lookups, of which 5 were spent on a vendor nobody had used in a year. Removing one dead include took it to 2. Count yours: the SPF checker resolves the whole tree, or write the recursion yourself, it's twenty lines. - Two SPF records. Publishing two
v=spf1TXT records is a permanent error, not a union. It happens when a second team adds a vendor without checking. Merge them.
DKIM
You can't enumerate selectors - DNS has no "list the names under this label" operation - so you have to know the selector before you can look up the key. Read it from the s= tag of the DKIM-Signature header on that failing message:
$ dig +short TXT selector1._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A..."
If you don't have a message to read, a DKIM checker probes the well-known names - but understand what "not found" means there. It means "no key at a name we guessed", not "no DKIM". That distinction matters more than tool authors usually admit: I recently ran a 65-name probe against a domain I administer and got nothing, then found three perfectly valid keys under selectors that weren't on the list.
Use 2048-bit keys. 1024 still validates but is deprecated in practice, and the large mailbox providers have signalled they intend to stop accepting it.
DMARC, and the alignment trap
$ dig +short TXT _dmarc.example.com
"v=DMARC1; p=none; rua=mailto:r******@example.com"
Now back to that header. DMARC does not ask "did SPF pass?" It asks "did SPF pass for a domain that aligns with the From header?" Same for DKIM. SPF alignment compares the From: domain against the envelope sender (smtp.mailfrom / Return-Path) - a domain your recipients never see and your ESP usually controls. DKIM alignment compares the From: domain against the signature's d= tag. DMARC passes if either aligns. Which is why the header above fails: SendGrid authenticated b*****@mail.example.com for SPF, the DKIM signature carried d=sendgrid.net, and the From header said example.com. Both mechanisms passed for domains that aren't yours.
Two dials control strictness, and both default to relaxed (r):
v=DMARC1; p=reject; adkim=s; aspf=s
Relaxed alignment accepts a subdomain of your organizational domain - mail.example.com aligns with example.com. Strict demands an exact match. Almost nobody needs strict, and turning it on is a reliable way to break your own mail. If you're setting adkim=s because it sounds more secure, don't.
The fix for a misaligned ESP is nearly always: configure a custom return-path / sending subdomain with the vendor, and have them sign with d= on your domain. Every serious platform supports this; it's usually one page in their settings called "domain authentication".
Forwarding breaks SPF, permanently
If the complaints come from one department or one partner, suspect forwarding before anything else. When a message is forwarded, the relaying server isn't in your SPF record, so SPF fails - through no fault of yours and with nothing you can publish to prevent it. DKIM usually survives, which is the real argument for having both. Mailing lists that append footers or rewrite subjects break DKIM too, and ARC exists to carry the original verdict across those hops - though it only helps if the receiver honours it.
Then read the reports
p=none with a rua= address costs nothing and turns speculation into data. Aggregate reports arrive as daily XML from every major receiver, listing each sending IP with its SPF and DKIM results. It's how you discover the marketing platform someone set up in 2023 that nobody remembers. Deploy in the obvious order: p=none until the reports are boring, then quarantine with a pct=, then reject. Jumping straight to reject on a domain you don't have reporting for is how you find out what else was sending as you - by breaking it.
Cause 2: reputation
Only once authentication is clean. Fixing reputation while DMARC fails is pouring water into a bucket with no bottom.
- Check the actual signals. Google Postmaster Tools and Microsoft SNDS both give you domain and IP reputation for free, and they are the only sources that reflect what those receivers actually think. Everything else is inference.
- Watch the spam complaint rate. Google's threshold is 0.3%, and you want to be under 0.1%. This is the metric with the sharpest cliff - crossing it degrades delivery for everything you send, transactional included.
- Check blocklists, but keep them in proportion. Spamhaus matters. Most of the eighty-entry blocklist tables you'll find online are dead or irrelevant, and being on some hobbyist list nobody queries is not your problem.
- Check the boring infrastructure. Forward-confirmed reverse DNS on your sending IP - PTR resolves to a hostname that resolves back to the same IP. TLS on transport. These are table stakes and they're occasionally just missing after a migration.
- Bulk senders have hard requirements now. Since February 2024, Google and Yahoo require senders of roughly 5,000+ messages a day to a given provider to have SPF and DKIM, publish a DMARC record, keep spam rates under that 0.3%, and support one-click unsubscribe per RFC 8058 - that's
List-Unsubscribe-Post: List-Unsubscribe=One-Click, honoured within two days. Microsoft has since introduced equivalent requirements for Outlook.com. If you're above that volume and missing any of it, you have found your answer and it isn't your subject lines.
Cause 3: content and engagement
Last, because it's where everyone starts and where the least leverage is. Engagement is what actually moves modern filters: opens, replies, and - most of all - people not marking you as spam. A clean list of people who asked to hear from you outperforms every subject-line trick. If you're mailing addresses harvested two years ago, no amount of DNS work saves you.
The specific things worth checking: you're not sending bulk marketing from the same domain as your transactional mail (separate subdomains, separate reputations), you have working unsubscribe, and you're removing hard bounces promptly. Spam-trap hits are disproportionately damaging.
The triage order, condensed
- Get full headers of a real failing message
- Read
Authentication-Resultsdmarc=fail,spf=pass,dkim=passโ alignment. Fix the ESP's return-path /d=spf=permerrorโ count lookups; you're over 10dkim=failโ key rotated, or a relay modified the message- all pass โ authentication is fine, go to step 3
- Postmaster Tools + SNDS: reputation and complaint rate vs 0.3%
- rDNS, TLS,
List-Unsubscribe, bulk-sender requirements - Only now: list hygiene, engagement, content
Most "going to spam" tickets die at step 2, and a large share of those are the alignment case - the one where everything says pass and the mail still fails.
If you want the whole picture for a domain without assembling it by hand, the DMARC checker reads all three records, counts the SPF lookups properly, and tells you what's actually wrong. It's free and there's no signup.
Comments
No comments yet. Start the discussion.