postfix-config: report addresses are relay recipients when the relay is on

Found by talking SMTP to port 25 of the test server once it answered
again (2026-10-10): RCPT TO:<dmarc-reports+bs.mixdep.ru@selfpost.mixfed.ru>
was refused with "550 5.1.1 User unknown in relay recipient table".

With INBOUND_RELAY_ENABLE and DMARC_REPORTS_ENABLE both true the server's
own name is a relay domain (for the reports) and relay_recipient_maps
lists the relay's recipients only. smtpd_reject_unlisted_recipient
applies after the restriction list, so the OK that
check_recipient_access gives a report address does not help: every
report was refused. The table of report addresses is added to
relay_recipient_maps in that combination.

Checked on the server by setting the parameter in the running container
and reloading Postfix: the domain's report address is answered 250, the
former server-wide mailbox and an unknown local part 550, a foreign
domain and an inbound domain without recipients 554. e2e: the combined
case requires relay_recipient_maps to name both tables.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-11 00:05:40 +03:00
co-authored by Claude Opus 5.5
parent 80748e6c94
commit 36db4223f2
3 changed files with 37 additions and 1 deletions
+19
View File
@@ -22,6 +22,9 @@ type port25Case struct {
name string
env []string
check []optionCheck
// main are main.cf parameters the combination must end up with, read with
// postconf -h.
main []optionCheck
}
var port25Cases = []port25Case{
@@ -61,6 +64,13 @@ var port25Cases = []port25Case{
{param: "smtpd_recipient_restrictions", contains: "check_recipient_access,texthash:/data/postfix/dmarc_recipients,reject_unauth_destination,reject_unlisted_recipient", wantExact: true},
{param: "smtpd_milters", contains: "", wantExact: true},
},
// Both on: the report addresses sit on a relay domain, and the relay's
// unlisted-recipient check runs after the restriction list. Unless their
// table is a recipient table too, every report is refused as "User
// unknown in relay recipient table".
main: []optionCheck{
{param: "relay_recipient_maps", contains: "texthash:/data/postfix/relay_recipients texthash:/data/postfix/dmarc_recipients", wantExact: true},
},
},
{
name: "inbound relay with antispam milter",
@@ -129,6 +139,15 @@ func checkPort25ConfigCombinations(s *stack) error {
return fmt.Errorf("%s: master.cf has -o %s = %q but Postfix reads %q - the value contains whitespace", tc.name, c.param, got, strings.TrimSpace(seen))
}
}
for _, c := range tc.main {
got, err := s.execIn("selfpost", "postconf", "-h", c.param)
if err != nil {
return fmt.Errorf("%s: postconf -h %s: %v\n%s", tc.name, c.param, err, got)
}
if got = strings.TrimSpace(got); got != c.contains {
return fmt.Errorf("%s: %s = %q, want %q", tc.name, c.param, got, c.contains)
}
}
}
// Back to the stand's own configuration: flags off, no port-25 listener.