SPF passed, and the message is still forged
"SPF check passed" does not mean the message is genuine. It means the sending server was authorised for its own domain — an entirely different claim.
"SPF check passed" does not mean the message is genuine. It means the sending server was authorised for its own domain — an entirely different claim.
A message carries two sender addresses, not one. The first is the envelope address — the return path given during the SMTP session. The second is the `From:` header, the address the user sees on screen.
SPF checks the first. So if an attacker puts their own domain in the envelope and yours in `From:`, SPF passes, because it never looks at `From:` at all.
That is why "SPF passed" does not rule out forgery. What ties the two addresses together has its own name: alignment.
DMARC takes the result of the two checks and adds one condition on top: does the domain that was checked match the domain in `From:`?
For SPF, the envelope domain is compared with the `From:` domain. For DKIM, the signing domain is compared with the `From:` domain. One of the two matching is enough.
So the right question is not "did SPF pass" but "did it align". A report that does not answer the second question is useless.
SPF is bound to the route: it looks at which server delivered the message. So forwarding — through a mailing list, say — breaks SPF, because the last hop is a different server.
DKIM is bound to the message: the signature covers headers and part of the body, and it travels with the message. Forwarding preserves it as long as the content is not modified.
In practice both are deployed. But if one has to come first, DKIM delivers more value and breaks less.
A DMARC policy takes one of three values: `none` — do nothing, just send reports; `quarantine` — put suspect mail in spam; `reject` — refuse it.
The right path starts at `none`. Nothing changes at that stage, but reports start arriving and you learn who sends mail as your domain. The list is nearly always longer than expected.
Then `quarantine`, and only then `reject`. Weeks should pass between the stages, because a system that sends once a month will not appear in the first week.
DMARC reports arrive as XML and are not human-readable. So the `rua` address is frequently pointed at a mailbox nobody opens.
Skipping that stage is what makes the move to `reject` dangerous: the reports are exactly what tells you whether it is safe. They list, per source, how many messages passed and how many failed alignment.
A practical note: look at a full month of reports before moving to `reject`. Monthly statements, payroll systems and annual notices are found on precisely that interval.
Most of the trouble comes not from your own server but from others: the marketing platform, the accounting system, the CRM, the monitoring service — all of them send mail as your domain.
Each has two options: let them sign for your domain with a DKIM key, or give them a dedicated subdomain. The second is considerably cleaner: if `mail.example.uz` fails, the main domain is untouched.
The SPF record has a limit of its own: no more than ten DNS lookups. Every new service brings you closer to it, and once exceeded SPF stops working altogether.
DMARC protects your domain only. It does nothing about a message whose `From:` carries an entirely different domain.
So the most common attack is built differently: the display name reads "Accounts Payable" while the address is unfamiliar. Many mobile mail clients show only the name.
The other variant is a lookalike domain, one letter swapped or inserted. That domain has its own correct SPF and DKIM and passes every check there is.
So the work starts by listing domains. Every domain that sends mail on behalf of the company goes on the list — and so does every domain that does not.
The non-sending ones matter separately: they get an empty SPF record and a `reject` policy. Otherwise they remain a ready-made instrument for an attacker.
And watching for lookalikes joins the list. A freshly registered similar name usually appears weeks before the attack does, which is time you can use.
Show us a domain and we will give you a first read on your current external posture. Nothing is changed at this stage.

