From 9904399d24388a9cf337a672434ad1be71010652 Mon Sep 17 00:00:00 2001 From: Steve Atkins Date: Mon, 17 Mar 2025 15:54:30 +0000 Subject: [PATCH] =?UTF-8?q?Accept=20and=20handle=20emails=20sent=20with=20?= =?UTF-8?q?an=20empty=20821.From=20/=20return-path=20as=E2=80=A6=20(#561)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Accept and handle emails sent with an empty 821.From / return-path as it would any other email. --- pkg/policy/address.go | 5 +++++ pkg/server/smtp/handler.go | 14 +------------- pkg/server/smtp/handler_test.go | 9 +++++++-- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/pkg/policy/address.go b/pkg/policy/address.go index bb60186..1f55957 100644 --- a/pkg/policy/address.go +++ b/pkg/policy/address.go @@ -75,6 +75,11 @@ func (a *Addressing) NewRecipient(address string) (*Recipient, error) { // ParseOrigin parses an address into a Origin. This is used for parsing MAIL FROM argument, // not To headers. func (a *Addressing) ParseOrigin(address string) (*Origin, error) { + if address == "" { + return &Origin{ + addrPolicy: a, + }, nil + } local, domain, err := ParseEmailAddress(address) if err != nil { return nil, err diff --git a/pkg/server/smtp/handler.go b/pkg/server/smtp/handler.go index 8643a33..b353f11 100644 --- a/pkg/server/smtp/handler.go +++ b/pkg/server/smtp/handler.go @@ -411,18 +411,6 @@ func (s *Session) parseMailFromCmd(arg string) { from := m[1] s.logger.Debug().Msgf("Mail sender is %v", from) - // Parse from address. - _, domain, err := policy.ParseEmailAddress(from) - s.logger.Debug().Msgf("Origin domain is %v", domain) - if from != "" && err != nil { - s.send("501 Bad sender address syntax") - s.logger.Warn().Msgf("Bad address as MAIL arg: %q, %s", from, err) - return - } - if from == "" { - from = "unspecified" - } - // Parse ESMTP parameters. if m[2] != "" { // Here the client may put BODY=8BITMIME, but Inbucket already @@ -480,7 +468,7 @@ func (s *Session) parseMailFromCmd(arg string) { // Ignore ShouldAccept if extensions explicitly allowed this From. if extAction == event.ActionDefer && !s.from.ShouldAccept() { s.send("501 Unauthorized domain") - s.logger.Warn().Msgf("Bad domain sender %s", domain) + s.logger.Warn().Msgf("Bad domain sender %s", origin.Domain) return } diff --git a/pkg/server/smtp/handler_test.go b/pkg/server/smtp/handler_test.go index 8658701..5c60144 100644 --- a/pkg/server/smtp/handler_test.go +++ b/pkg/server/smtp/handler_test.go @@ -78,6 +78,11 @@ func TestGreetState(t *testing.T) { } } +// Messages sent with a null reverse-path are unusual, +// but valid. They are used for delivery status +// notifications, and also for some sorts of auto-responder +// as part of bounce storm mitigation. +// Sections 3.6.3 and 4.5.5 of RFC 5321 discuss them. func TestEmptyEnvelope(t *testing.T) { ds := test.NewStore() server := setupSMTPServer(ds, extension.NewHost()) @@ -85,14 +90,14 @@ func TestEmptyEnvelope(t *testing.T) { // Test out some empty envelope without blanks script := []scriptStep{ {"HELO localhost", 250}, - {"MAIL FROM:<>", 501}, + {"MAIL FROM:<>", 250}, } playSession(t, server, script) // Test out some empty envelope with blanks script = []scriptStep{ {"HELO localhost", 250}, - {"MAIL FROM: <>", 501}, + {"MAIL FROM: <>", 250}, } playSession(t, server, script) }