+++ date = '2025-08-01T10:03:15+02:00' draft = false title = 'Blocking Invalid Recipients Before They Reach Your Exchange Server' [cover] image = "/imgs/email-route.jpg" alt = "Email App icon on blue background" caption = "" +++ Recently, I had to deal with a serious problem: **backscatter**. One of our mail gateways ended up listed on the **backscatter.org** blacklist for sending bounce messages to forged senders. After checking the logs, I quickly realized that our system wasn't actually protected against backscatter attacks, so I had to do something about it. ## What Even Is Backscatter? Backscatter is unwanted email that your mail server sends **after** receiving a message, usually in the form of a **non-delivery report (NDR)** or **bounce** to a **forged sender address**. It happens when: - A spammer sends email with a **fake "From" address** (often an innocent third party). - Your mail server **accepts** the message first, but later discovers it’s undeliverable. - Your server sends a **bounce** to the forged address, hitting an innocent person instead of the spammer. This makes your server appear to be sending spam, even though you're just bouncing bad mail. ## The Problem in Our Setup Our mail gateway mostly relays mail to multiple internal Exchange Server clusters. We have a list of valid domains configured, so Postfix will only accept mail for those domains. **The problem?** Postfix didn't know which individual recipients were valid on the downstream Exchange servers. That meant it would happily accept messages for **nonexistent users**, only to later bounce them, classic backscatter behavior. ## The Goal We needed to reject mail **during the SMTP session**, ideally right after the `RCPT TO` command, if the recipient didn't exist on the Exchange servers. That way, the sending server would get the rejection immediately, and we would never have to generate a bounce message. ## Possible Solutions I Considered ### **1. relay_recipient_maps** This would require maintaining a **full list of valid recipients** in a Postfix lookup table. It works well, but means writing and maintaining a script to **sync the list from Active Directory** on a regular basis. For us, this was too much custom scripting, too fragile, and too messy to maintain. ### **2. virtual_mailbox_maps with LDAP** Another approach would be using **LDAP lookups** directly against Active Directory to verify recipients in real-time. This can work in some setups, but: - It adds complexity and dependencies. - It can introduce security concerns. - It didn’t fit well with our environment. So I ruled it out. ## The Solution: `reject_unverified_recipient` While reading through the **Postfix Address Verification Howto**, I came across the `reject_unverified_recipient` option - bling! - exactly what I needed. ### **How It Works** When an incoming SMTP session reaches the `RCPT TO` stage: 1. Postfix checks if `reject_unverified_recipient` is enabled for the recipient domain. 2. If yes, it temporarily **probes the downstream mail system** to see if the recipient address exists. 3. If the downstream system says: - **User exists** → Postfix continues processing. - **User does not exist** → Postfix **rejects immediately** with: ``` 550 5.1.1 : Recipient address rejected: User unknown ``` Because the rejection happens **during SMTP**, no bounce is generated, and backscatter is avoided entirely. ## Implementation in ISPConfig In our case, the mail gateways run **Postfix** with **ISPConfig** as the management interface. I implemented a new configuration option in ISPConfig for **per-domain control** of `reject_unverified_recipient`, along with a **validation server** to specify for the downstream validation server. ### Specifying a Validation Server for Recipient Verification One important detail is that Exchange servers cannot validate recipients over the default SMTP transport on port `25`. To enable recipient validation, you need to activate it on the Exchange server and use the Hub Transport service, which by default runs on port `2525`. Make sure to restrict access to this port, as it requires anonymous login specifically for recipient validation, you don't want that exposed broadly. > **Note:** This setup does not affect your regular mail flow. Only the SMTP probes used for verifying recipients are sent to this validation server. > Postfix enables this behavior with the `address_verify_transport_maps` option. To optimize performance and reduce unnecessary verification probes for addresses that have already been checked, I configured a local cache on the mail gateway using the `address_verify_map` option. This way, repeated probes for the same recipient are avoided. Now, for domains that need recipient verification, we can enable it in the panel and point Postfix to the appropriate **validation transport**. ## The Result After enabling `reject_unverified_recipient` and pointing it at the Exchange clusters, the backscatter stopped completely. We were no longer accepting messages for invalid recipients. ## Conclusion If your Postfix server is acting as a relay for Exchange (or any downstream mail system) and you're struggling with **backscatter spam**, enabling `reject_unverified_recipient` can be a clean and effective fix. It avoids maintaining large static recipient maps, works dynamically, and ensures that invalid mail is rejected **before** it ever gets into your system.