Generate the relay config from the environment at container start
(build/postfix-config.sh, run from entrypoint.sh):
- smtps 465 (implicit TLS) primary + optional submission 587 (STARTTLS),
chroot=n so smtpd reaches the sasldb2/sender map under /data.
- Cyrus SASL against the panel-maintained sasldb2; realm left implicit so the
authenticated name equals the bare login in smtpd_sender_login_maps.
- reject_sender_login_mismatch + relay/recipient restrictions with no
permit_mynetworks: credentials-only, open relay impossible (spec 5, 5.1).
- TLS cert/key from TLS_CERT_FILE/TLS_KEY_FILE; daily postfix reload picks up
renewed certs (postfix-cert-reload.sh under supervisord, spec 5.2).
- anvil level-1 rate limit from env (spec 5 p.5).
- Milter chain with per-milter action: OpenDKIM strict (tempfail), journal
fail-open (accept) so monitoring never blocks the relay (spec 7.3).
Two integration fixes found on the server:
- postconf -F '*/*/chroot=n': Debian's chrooted delivery agent can't read
/etc/resolv.conf, so MX lookups failed and mail never left.
- entrypoint sets /run/opendkim and /run/selfpost to group selfpost + setgid,
and the journal stub chmods its socket 0660, so postfix can connect to both
milter sockets (strict OpenDKIM was milter-rejecting all mail otherwise).
Verified on selfpost.mixfed.ru: gofmt/vet/test green, image builds; container
e2e — 465 auth+send DKIM-signed (d=domain,s=selfpost), 587 STARTTLS auth,
cross-domain sender 553, list-mode per-address binding, unauth relay 554,
real outbound delivery reaching the recipient MX over TLS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>