The Full Stop That Isn't: A Safe SMTP Smuggling Audit for Your Mail Chain
Photo: Wikideas1, CC0, via Wikimedia Commons
Every email has a full stop. In SMTP, the one that matters is a line containing a single dot, wrapped in carriage returns and line feeds. It tells the server: that is the lot, deliver the message. The trouble starts when two servers in the same chain disagree about which version of that full stop counts. That disagreement has a name — SMTP smuggling — and it is less exotic than it sounds.
The trick in plain English
SMTP has a DATA phase. The client sends headers and body, then ends the message with a specific sequence: carriage return, line feed, a dot, carriage return, line feed. A well-behaved server also dot-stuffs the body, so a legitimate line beginning with a dot is escaped rather than mistaken for the terminator.
SMTP smuggling exploits inconsistent handling of that terminator. Depending on the direction of the mismatch, an attacker can use a bare line feed before and after the dot — LF dot LF — or another variant that one server accepts and another does not. If an outbound relay lets the sequence through without escaping it, and the receiving server treats it as end-of-data, the message can split. The first part looks like ordinary mail. Everything after the dot can become a second message, with its own headers and its own intent.
The scary bit is not the dot itself. It is the gap between two systems that both believe they are doing the right thing. One filters what it thinks is a single message; another accepts what looks like a fresh one. If those two views do not line up, a filter can be looking at the wrong thing entirely.
Why UK mail stacks still care in 2026
The vulnerability class was publicly documented in 2023, and patches have been available for the major mail servers. That does not mean every hop in every UK organisation has been updated. Real mail chains are messy. A small firm might have a website on a shared cPanel or Plesk box, a transactional sender, a domain registrar forwarder, an ISP smart host, and a filtering gateway bought through an MSP. Each hop is a chance for a different interpretation of the same three bytes.
Legacy relays are the obvious candidate. So are appliances that were set up years ago and have not been touched since, and forwarding rules that were bolted on during a migration. Shared hosting panels deserve a special mention because they often pin an older daemon and expose few knobs. You may not control the version, but you still need to know whether that hop rejects bare newlines or quietly accepts them.
There is also the inherited-config problem. A configuration that was fine for a single-domain setup can become risky when the same relay starts handling several domains, catch-all addresses, or mailing lists. The more places a message can be re-queued or forwarded, the more chances there are for one link in the chain to disagree with the next.
Do not test this on the live fire
It is tempting to fire malformed SMTP at your production MX and see what happens. Please do not. You can create mail loops, trip rate limits, confuse anti-abuse systems, or leave a very odd support ticket for someone else to clean up. A smuggling test is a boundary test, and boundary tests belong in a controlled environment.
Use a test domain, a staging relay, and a mailbox you own. If you rely on a hosting provider or managed filter, ask whether they have a test endpoint or a documented way to validate DATA handling. Get permission before you send anything unusual through a shared platform. And keep the payload boring: a marker string, a second marker, no real credentials, no live customer data.
A safe audit sequence
Start with an inventory, not a packet. List every hop a message takes: submission client, outbound relay, inbound MX, filtering gateway, forwarding rule, mailing list, and final mailbox. You cannot reason about a mismatch if you do not know where the boundaries are.
Next, check versions and configuration against vendor guidance. Look specifically at how each server handles bare newlines during DATA. On Postfix, for example, the relevant hardening controls and defaults have changed across releases, so read the documentation for your version rather than trusting a blog post from years ago. On Exim and appliance-based gateways, check the vendor advisory and confirm whether the fix is actually enabled, not merely installed.
Then build a small harness. Send a controlled message that contains a harmless marker, followed by a bare LF dot LF sequence, followed by a second marker. Run it through each hop you can safely test. The question is simple: does the next hop see one message or two? Does the filter verdict change? Does the final mailbox receive a separate message, or does the second marker appear as body text? All three outcomes tell you something useful.
Do not forget outbound escaping. Send a legitimate body line containing a single dot and confirm the relay dot-stuffs it correctly. A relay that is relaxed about bare newlines on the way in may also be relaxed about escaping on the way out. You want both directions to agree.
Finally, compare filter verdicts at each stage. If your gateway sees one message and your mailbox sees two, you have found a boundary problem. If the gateway sees two but only scans the first, that is worse. Log the results, fix the hop that disagrees, and retest the whole chain rather than just the patched box.
What good looks like
A healthy chain rejects bare newlines in DATA, uses consistent CRLF handling, dot-stuffs correctly, and keeps every relay patched. It also documents exceptions. If an ancient line-of-business app genuinely needs a relaxed relay, isolate that relay and make sure it cannot pass malformed DATA into the rest of the estate.
DMARC, SPF, and DKIM still matter, but they are not a substitute for getting the SMTP boundary right. Authentication tells you who claims to have sent a message. It does not tell you whether your filter and your mailbox agree on where that message ends.
SMTP smuggling is a dispute about punctuation. Audit the boundaries, keep the tests safe, and make sure every hop is reading from the same script.