Here is a consolidated set of best practices for running Stalwart behind an inbound AV/spam filtering relay (the “Sender → AV relay → Stalwart → Recipient” topology):
1. Preserve the real client IP via Proxy Protocol
The AV relay is just another SMTP proxy. Without knowing the original sender’s IP, Stalwart’s SPF/DMARC checks, rate-limiting, and auto-banning all run against the relay’s IP, which is useless (and will self-ban your relay).
- Configure the relay to emit Proxy Protocol headers on its connections to Stalwart.
- On Stalwart’s listener, enable Proxy Protocol acceptance and mark the relay’s IP as a trusted network.
Docs: Reverse proxy overview - Preserving the client IP and Proxy Protocol
2. Use a dedicated listener for the relay
Create a separate SMTP listener (e.g. on a private interface or non-standard port) exclusively for your AV relay. This lets you write targeted expressions for just that listener, e.g.:
{"name": "relay-in", "protocol": "smtp", "bind": ["127.0.0.1:10025"]}
Docs: Listeners
3. Disable Stalwart’s built-in spam filter for the relay listener
Since the AV relay has already scanned the message, you don’t want Stalwart to re-scan it. The enableSpamFilter field in the DATA stage accepts an expression - scope it to skip your relay listener:
{
"enableSpamFilter": {
"match": [{"if": "listener == 'relay-in'", "then": "false"}],
"else": "is_empty(authenticated_as)"
}
}
Docs: Inbound DATA - Spam filtering
4. Relax or bypass SPF/DKIM/DMARC checks for the relay
SPF will legitimately fail when the relay re-sends mail, since its IP is not in the sender’s SPF record. Use the remote_ip or listener variables in the SenderAuth expressions (spfVerify, dkimVerify, dmarcVerify) to set them to disable or relaxed for connections from the relay.
Docs: DMARC Verification, SenderAuth object
5. Restrict the relay-in listener to the relay’s IP only
Use the isClientAllowed / connection-stage expression or firewall rules to ensure only your relay can connect to this listener - preventing it from becoming an open relay. If you want Stalwart to accept relayed mail (to local recipients) from the relay without authentication, adjust allowRelaying scoped to that listener’s IP:
{
"allowRelaying": {
"match": [{"if": "listener == 'relay-in' && remote_ip == '10.0.0.1'", "then": "true"}],
"else": "!is_empty(authenticated_as)"
}
}
Docs: Inbound RCPT - Relay
6. (Optional) Trust X-Spam headers from the relay
If your AV relay adds X-Spam-Status or similar headers, you can write a Sieve rule or MTA Hook to consume those and act on them instead of running Stalwart’s own filter.
Docs: MTA Hooks, Sieve scripting
In summary: create a dedicated listener for the relay, enable Proxy Protocol so the real sender IP flows through, scope spam/auth checks to skip that listener, and lock down allowRelaying to the relay’s IP only.
This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.