Step 3/12 of docs/plans/inbound-antispam-panel.md. The panel serves a second milter while the inbound relay is on (internal/milter/inbound.go, socket INBOUND_JOURNAL_MILTER_SOCKET, default /run/selfpost/inbound-journal.sock). build/postfix-config.sh puts it last on port 25, after the optional antispam milter, with default_action=accept; postfix-wrapper.sh waits for its socket. At end-of-message it writes one inbound_spam_log row per recipient at an inbound domain - other port-25 recipients (DMARC report addresses) get none - and always accepts. With a filter attached it reads the verdict from X-Rspamd-Action and X-Spamd-Result (action, score, up to six weighted symbols, only what the patterns recognise, 255 bytes); without one those headers are the sender's and are not read. The plan named X-Rspamd-Score, which rspamd does not have. The antispam compose fragment mounts rspamd/milter_headers.conf into the sidecar so that it adds the two headers (checked in rspamd 3.11: both routines exist and remove a sender's own headers of those names). Store: InsertInboundSpam, IsInboundDomain. Checked on the test server, uncommitted tree: go vet ./... ok, go test ./... ok (22 packages), make e2e ok - the relayed message of inbound_relay_delivers_and_refuses has its journal row (accept by selfpost) and the DMARC report sent through the same listener has none. Not yet seen in a real run: a verdict written by rspamd reaching this milter. The e2e stand has no filter, and the test server's only inbound domain has no upstream, so it accepts no mail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
33 lines
1.4 KiB
YAML
33 lines
1.4 KiB
YAML
# Optional anti-spam sidecar for inbound relay (docs/plans/inbound-relay.md).
|
|
#
|
|
# SelfPost does not ship or start an anti-spam engine. This fragment brings up
|
|
# rspamd next to SelfPost and points the inbound smtpd milter at it. Merge it
|
|
# only when you want filtering on port 25:
|
|
#
|
|
# docker compose -f docker-compose.yml -f antispam/docker-compose.antispam.yml up -d
|
|
#
|
|
# Requires INBOUND_RELAY_ENABLE=true in .env. The milter sees the real client
|
|
# IP, HELO and PTR — unlike the upstream, which only sees SelfPost's address.
|
|
#
|
|
# Pin the rspamd tag the same way the SelfPost image is pinned; bump it
|
|
# deliberately. Default milter action is fail-open (accept) so a down sidecar
|
|
# does not block backup-MX. Set INBOUND_ANTISPAM_MILTER_ACTION=tempfail to
|
|
# defer instead.
|
|
|
|
services:
|
|
selfpost:
|
|
environment:
|
|
INBOUND_RELAY_ENABLE: "${INBOUND_RELAY_ENABLE:-true}"
|
|
INBOUND_ANTISPAM_MILTER: "${INBOUND_ANTISPAM_MILTER:-inet:antispam:11332}"
|
|
INBOUND_ANTISPAM_MILTER_ACTION: "${INBOUND_ANTISPAM_MILTER_ACTION:-accept}"
|
|
depends_on:
|
|
- antispam
|
|
|
|
antispam:
|
|
image: rspamd/rspamd:3.11
|
|
restart: unless-stopped
|
|
# No host ports: only SelfPost talks to the milter on the compose network.
|
|
volumes:
|
|
# The verdict headers SelfPost's inbound journal reads.
|
|
- ./antispam/rspamd/milter_headers.conf:/etc/rspamd/local.d/milter_headers.conf:ro
|