From 046de42774bee11cf4baca45491e604e30db2c6a Mon Sep 17 00:00:00 2001 From: Sascha Andres Date: Sat, 25 Jul 2020 19:23:31 +0200 Subject: [PATCH] allow empty envelope (#166) * feat: allow empty MAIL FROM Closes #164 --- pkg/server/smtp/handler.go | 7 +++++-- pkg/server/smtp/handler_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/pkg/server/smtp/handler.go b/pkg/server/smtp/handler.go index bcedfe6..f3a8e0c 100644 --- a/pkg/server/smtp/handler.go +++ b/pkg/server/smtp/handler.go @@ -41,7 +41,7 @@ const ( // accepting '>' as quoted pair and in double quoted strings (?i) makes the regex case insensitive, // (?:) is non-grouping sub-match var fromRegex = regexp.MustCompile( - "(?i)^FROM:\\s*<((?:\\\\>|[^>])+|\"[^\"]+\"@[^>]+)>( [\\w= ]+)?$") + "(?i)^FROM:\\s*<((?:(?:\\\\>|[^>])+|\"[^\"]+\"@[^>])+)?>( [\\w= ]+)?$") func (s State) String() string { switch s { @@ -314,11 +314,14 @@ func (s *Session) readyHandler(cmd string, arg string) { return } from := m[1] - if _, _, err := policy.ParseEmailAddress(from); err != nil { + if _, _, err := policy.ParseEmailAddress(from); 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" + } // This is where the client may put BODY=8BITMIME, but we already // read the DATA as bytes, so it does not effect our processing. if m[2] != "" { diff --git a/pkg/server/smtp/handler_test.go b/pkg/server/smtp/handler_test.go index 5aa3e35..bcb61d8 100644 --- a/pkg/server/smtp/handler_test.go +++ b/pkg/server/smtp/handler_test.go @@ -79,6 +79,35 @@ func TestGreetState(t *testing.T) { } } +// Test commands in READY state +func TestEmptyEnvelope(t *testing.T) { + ds := test.NewStore() + server, logbuf, teardown := setupSMTPServer(ds) + defer teardown() + + // Test out some empty envelope without blanks + script := []scriptStep{ + {"HELO localhost", 250}, + {"MAIL FROM:<>", 250}, + } + if err := playSession(t, server, script); err != nil { + // Dump buffered log data if there was a failure + _, _ = io.Copy(os.Stderr, logbuf) + t.Error(err) + } + + // Test out some empty envelope with blanks + script = []scriptStep{ + {"HELO localhost", 250}, + {"MAIL FROM: <>", 250}, + } + if err := playSession(t, server, script); err != nil { + // Dump buffered log data if there was a failure + _, _ = io.Copy(os.Stderr, logbuf) + t.Error(err) + } +} + // Test commands in READY state func TestReadyState(t *testing.T) { ds := test.NewStore()