omeryanbas.com

Ömer Yanbaş

General Manager, Ticofab Yazılım

IntegrationsMessaging

Mail lands in spam: the From alignment nobody checks

SPF and DKIM can both pass while mail keeps landing in spam. The header that explains it names three domains, and DMARC only accepts one answer.

A platform we run delivers campaign mail through several servers. Authentication was configured on every one of them, the usual checkers reported SPF and DKIM as passing, and a large share of the mail still landed in spam or disappeared with no bounce at all. The header that explained it was present on every message and nobody had read it. The domain the reader saw in From and the domain that actually authenticated the message were different, so DMARC alignment failed.

What the three records actually do

SPF publishes the list of addresses allowed to send for a domain. The domain it checks is the envelope sender, the address bounces go back to, which is not the one the reader sees.

DKIM signs the message with a private key held on the sending server and publishes the matching public key in DNS. The signature carries a d= tag naming the signing domain. A receiver recomputes the hash and sees whether the signature holds.

DMARC is a policy published on the domain in the visible From header, and it asks a narrower question than the other two: did SPF or DKIM pass for a domain that matches the From domain. That match is alignment, and it is the part that gets skipped.

Relaxed alignment, which is the default, accepts an organizational domain match, so mail.brand.example aligns with brand.example. Strict alignment requires the exact domain. Either way, a pass on an unrelated domain is worth nothing to DMARC.

Now the setup that produces the failure. The platform delivers through several servers. Each has its own hostname, its own domain, its own SPF record and its own DKIM key, all of them correct. The platform is configured to put one brand address in the From header of every message, whichever server sends it. The result:

  • SPF passes for the delivery server's domain.
  • DKIM passes with d= set to the delivery server's domain.
  • The From header says the brand domain.
  • DMARC needs one of the first two to match the third, finds neither, and fails.

Every tool that looks at SPF and DKIM on their own reports green. Receivers that only require authentication to exist let the mail through. Receivers that enforce alignment quarantine it or drop it silently. That is why the symptom looks random: some mailboxes fine, some spam, some nothing.

How to see it

Send one message to a seed address you control at a large mailbox provider, open the original source, and read a single header.

Authentication-Results: mx.provider.example;
       spf=pass (sender IP is 203.0.113.10)
        smtp.mailfrom=mail7.sending.example;
       dkim=pass (signature was verified)
        header.d=mail7.sending.example;
       dmarc=fail (p=NONE sp=NONE dis=NONE)
        header.from=brand.example

Three lines, three domains. smtp.mailfrom is what SPF checked, header.d is what DKIM signed, header.from is what the reader sees. When the first two do not match the third, dmarc=fail follows, whatever the rest of the report says.

The DNS side takes two commands:

dig +short TXT brand.example | grep spf1
# "v=spf1 include:_spf.sending.example ~all"

dig +short TXT _dmarc.brand.example
# "v=DMARC1; p=none; rua=mailto:dmarc@brand.example; adkim=r; aspf=r"

p=none means the policy is reporting only, which is where everyone starts. adkim and aspf are the alignment modes, r for relaxed and s for strict.

The fix

There are two honest ways to align, and they suit different setups.

Keep one domain for everything. Every server signs with the same key, bounces to the same domain, and the From header stays as it is. It aligns, and it puts every server behind a single reputation. The cost is operational: the same private key has to exist on every machine, and the SPF record has to cover every sending address inside the limit of ten DNS lookups, which nested includes eat quickly.

Or let each server send as itself. This is what I prefer when servers come and go. The envelope sender and the DKIM signature use the server's own domain, and the From header is rewritten to that domain as well, while the display name stays the brand:

From: Brand Name <news@mail7.sending.example>
Reply-To: Brand Name <hello@brand.example>

The reader sees the brand in the message list, because clients show the display name and hide the address. Replies land on the main domain, because Reply-To says so. DMARC passes, because all three domains agree.

In a sending platform this is usually a per server option that forces the From header instead of keeping whatever the campaign specified. Turn it on for every server, not only the new ones. One server still sending the old way keeps producing the failures you are trying to explain, and it will be the one you forget about, in the same way a control panel and a config file quietly stop agreeing after somebody edits one of them by hand.

Then publish DMARC and raise it in steps. Start at p=none with a rua address, read the aggregate reports for two or three weeks, move to p=quarantine with a percentage, then to p=reject. Going straight to reject before the reports are clean means rejecting your own mail.

What this does not fix: content, list quality and complaint rate. Alignment gets you judged on reputation instead of refused at the door.

How to check it worked

Send to seed addresses at three different providers, save the raw messages and read the same header out of each one:

grep -io "spf=pass\|dkim=pass\|dmarc=pass\|smtp.mailfrom=[^;]*\|header.d=[^;]*\|header.from=.*" seed-*.eml
# spf=pass
# smtp.mailfrom=mail7.sending.example
# dkim=pass
# header.d=mail7.sending.example
# dmarc=pass
# header.from=mail7.sending.example

Three domains, one value. A few days later the aggregate reports should say the same thing at volume: nearly every message with a DMARC pass, and every source listed in the report a server you recognise. An unfamiliar address in those reports is either a forwarder or somebody sending as you, and both are worth an hour of your time.

What to watch out for

  • The ten lookup limit in SPF is counted across nested includes, and going over it produces a permanent error that most receivers treat as having no SPF at all. Count the lookups before you add another include, not after mail starts failing.
  • Forwarding breaks SPF, because the forwarding server is not in your record. DKIM survives forwarding as long as the body is not modified, so DKIM alignment is the one worth getting right first.
  • A new sending domain has no reputation, and a subdomain does not inherit much from its parent. Ramp volume slowly and hold whenever complaints or bounces move.
  • Nothing in the interface shows which domain authenticated. The display name is identical either way, so the only place the truth lives is a header inside somebody else's mailbox. Make reading it part of the release check, with the same reflex that catches security headers vanishing because of a config rule you assumed did not apply.

Mail authentication fails quietly by design. A receiver that drops an unaligned message owes you no explanation, and the only record of the decision is a header in a mailbox you do not own. Keep one seed address at each of the large providers, read Authentication-Results after every change to the sending setup, and treat the three domains in it as one check that either matches or does not. It costs a minute per change, and it is the difference between mail that gets judged on its merits and mail that is never seen.

Questions and answers

What does DMARC alignment mean?
Alignment means the domain that passed authentication is the same domain the reader sees in the From header. SPF is checked against the envelope sender and DKIM against the d= tag in the signature, and DMARC passes only if at least one of those matches the From domain. Relaxed alignment accepts a subdomain of the same organizational domain, strict alignment requires an exact match.
Why does a test tool say SPF and DKIM pass while mail still goes to spam?
Most quick checks look at each record in isolation and report a pass for whichever domain was authenticated. They do not compare that domain with the one in the From header. If your delivery server authenticates as itself and the From header says your brand, every record is valid and DMARC still fails, which is exactly the state that gets mail filtered.
Can I keep my brand name visible if each server sends from its own domain?
Yes. Mail clients show the display name, not the address, in the message list. Set the display name to the brand, put the server domain in the address so it aligns with SPF and DKIM, and add a Reply-To on your main domain so replies land where a person reads them.
How quickly can I raise volume on a new sending domain?
Start at a few hundred messages a day, double every second or third day, and stop increasing the moment complaint or bounce rate moves. A domain with no history that suddenly sends a hundred thousand messages gets filtered on volume alone, however good its authentication is. Warm up per domain and per address, because reputation is tracked for both.