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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user