+++
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 <user@example.de>: 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.

