From 50486ebde7160f3c95e07820f201fa64f79bfdb8 Mon Sep 17 00:00:00 2001 From: Vladislav Trotsenko Date: Thu, 16 Nov 2023 22:16:46 +0100 Subject: [PATCH 1/4] Technical/Update tests (#159) * Updated test helpers --- test_helpers_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test_helpers_test.go b/test_helpers_test.go index 03a100d..239e395 100644 --- a/test_helpers_test.go +++ b/test_helpers_test.go @@ -128,12 +128,10 @@ func runSuccessfulSMTPSession(hostAddress string, portNumber int, fullFlow bool) } } + // client.Quit() will close connection after, so we don't need to use client.Close() after if err = client.Quit(); err != nil { return err } - if err = client.Close(); err != nil { - return err - } return nil } From ee2f518c44e0676d65e1c75d9c8f30d98a59ce08 Mon Sep 17 00:00:00 2001 From: Vladislav Trotsenko Date: Wed, 27 Dec 2023 10:25:41 +0100 Subject: [PATCH 2/4] Technical/Updated CircleCI config (#161) * Updated CircleCI config * Updated .tool-versions --- .circleci/config.yml | 4 ++-- .tool-versions | 2 +- handler_data_test.go | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0490584..f497cab 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,12 +5,12 @@ version: 2.1 defaults: &defaults working_directory: ~/go-smtp-mock docker: - - image: cimg/go:1.19 + - image: cimg/go:1.21.5 jobs: linters: docker: - - image: golangci/golangci-lint:v1.50.1-alpine + - image: golangci/golangci-lint:v1.55.2-alpine steps: - checkout diff --git a/.tool-versions b/.tool-versions index b090305..3eaf48e 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -golang 1.15.6 +golang 1.21.5 diff --git a/handler_data_test.go b/handler_data_test.go index 9d64eb5..5ccdfb9 100644 --- a/handler_data_test.go +++ b/handler_data_test.go @@ -94,11 +94,13 @@ func TestHandlerDataClearMessage(t *testing.T) { } func TestHandlerDataProcessIncomingMessage(t *testing.T) { - handlerMessage := &handlerMessageMock{} - handler := &handlerData{handlerMessage: handlerMessage} - handler.handlerMessage = handlerMessage - handlerMessage.On("run").Once().Return(nil) - handler.processIncomingMessage() + t.Run("when successful request received", func(t *testing.T) { + handlerMessage := &handlerMessageMock{} + handler := &handlerData{handlerMessage: handlerMessage} + handler.handlerMessage = handlerMessage + handlerMessage.On("run").Once().Return(nil) + handler.processIncomingMessage() + }) } func TestHandlerDataWriteResult(t *testing.T) { From 13b462e367346d5946c338bca3431ffc6edc9d2e Mon Sep 17 00:00:00 2001 From: Vladislav Trotsenko Date: Wed, 27 Dec 2023 10:54:10 +0100 Subject: [PATCH 3/4] Feature/Localhost as valid domain name for MAILFROM, RCPTTO commands (#160) * Updated consts * Updated MAILFROM handler, tests * Updated RCPTTO handler, tests * Updated changelog --- CHANGELOG.md | 8 ++++++++ consts.go | 8 ++++---- handler_mailfrom_test.go | 10 ++++++++++ handler_rcptto_test.go | 9 +++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffeedb2..37489d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.0] - 2023-12-27 + +### Added + +- Added ability to use `localhost` as valid domain name for `MAIL FROM` and `RCPT TO` commands. Thanks [@Deracination](https://github.com/Deracination) for request + ## [2.1.0] - 2023-06-14 +### Added + - Added ability to use `NOOP` command, following [RFC 2821](https://datatracker.ietf.org/doc/html/rfc2821#section-4.1.1.9) (section 4.1.1.9). Thanks [@rehleinBo](https://github.com/rehleinBo) for PR ## [2.0.5] - 2023-01-11 diff --git a/consts.go b/consts.go index 5c6684b..c55a390 100644 --- a/consts.go +++ b/consts.go @@ -43,16 +43,16 @@ const ( defaultShutdownTimeout = 1 // in seconds defaultSessionResponseDelay = 0 // in seconds serverStartMsg = "SMTP mock server started on port" - serverStartErrorMsg = "unable to start SMTP mock server. Server must be inactive" + serverStartErrorMsg = "Unable to start SMTP mock server. Server must be inactive" serverErrorMsg = "Failed to start SMTP mock server on port" - serverStopErrorMsg = "unable to stop SMTP mock server. Server must be active" + serverStopErrorMsg = "Unable to stop SMTP mock server. Server must be active" serverNotAcceptNewConnectionsMsg = "SMTP mock server is in the shutdown mode and won't accept new connections" serverStopMsg = "SMTP mock server was stopped successfully" serverForceStopMsg = "SMTP mock server was force stopped by timeout" // Regex patterns availableCmdsRegexPattern = `(?i)helo|ehlo|mail from:|rcpt to:|data|rset|noop|quit` - domainRegexPattern = `(?i)([\p{L}0-9]+([\-.]{1}[\p{L}0-9]+)*\.\p{L}{2,63})` + domainRegexPattern = `(?i)([\p{L}0-9]+([\-.]{1}[\p{L}0-9]+)*\.\p{L}{2,63}|localhost)` emailRegexPattern = `(?i)?` ipAddressRegexPattern = `(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}` addressLiteralRegexPattern = `|\[` + ipAddressRegexPattern + `\]` @@ -64,7 +64,7 @@ const ( validRsetCmdRegexPattern = `\A(?i)rset\z` validNoopCmdRegexPattern = `\A(?i)noop\z` validQuitCmdRegexPattern = `\A(?i)quit\z` - validHeloComplexCmdRegexPattern = `\A(` + validHeloCmdsRegexPattern + `) (` + domainRegexPattern + `|localhost|` + ipAddressRegexPattern + addressLiteralRegexPattern + `)\z` + validHeloComplexCmdRegexPattern = `\A(` + validHeloCmdsRegexPattern + `) (` + domainRegexPattern + `|` + ipAddressRegexPattern + addressLiteralRegexPattern + `)\z` validMailromComplexCmdRegexPattern = `\A(` + validMailfromCmdRegexPattern + `) ?(` + emailRegexPattern + `)\z` validRcpttoComplexCmdRegexPattern = `\A(` + validRcpttoCmdRegexPattern + `) ?(` + emailRegexPattern + `)\z` diff --git a/handler_mailfrom_test.go b/handler_mailfrom_test.go index 4cb4ace..d10f3f4 100644 --- a/handler_mailfrom_test.go +++ b/handler_mailfrom_test.go @@ -184,6 +184,16 @@ func TestHandlerMaifromIsInvalidCmdArg(t *testing.T) { assert.Empty(t, message.mailfromResponse) }) + t.Run("when request includes valid command MAILFROM argument with localhost domain", func(t *testing.T) { + message := new(Message) + handler := newHandlerMailfrom(session, message, configuration) + + assert.False(t, handler.isInvalidCmdArg("MAIL FROM: user@localhost")) + assert.False(t, message.mailfrom) + assert.Empty(t, message.mailfromRequest) + assert.Empty(t, message.mailfromResponse) + }) + t.Run("when request includes valid command MAILFROM argument without <> sign without space", func(t *testing.T) { message := new(Message) handler := newHandlerMailfrom(session, message, configuration) diff --git a/handler_rcptto_test.go b/handler_rcptto_test.go index 0e9664b..7933860 100644 --- a/handler_rcptto_test.go +++ b/handler_rcptto_test.go @@ -288,6 +288,15 @@ func TestHandlerRcpttoIsInvalidCmdArg(t *testing.T) { assert.Empty(t, message.rcpttoRequestResponse) }) + t.Run("when request includes valid command RCPTTO argument with localhost domain", func(t *testing.T) { + message := new(Message) + handler := newHandlerRcptto(session, message, configuration) + + assert.False(t, handler.isInvalidCmdArg("RCPT TO: user@localhost")) + assert.False(t, message.rcptto) + assert.Empty(t, message.rcpttoRequestResponse) + }) + t.Run("when request includes valid command RCPTTO argument without <> sign without space", func(t *testing.T) { message := new(Message) handler := newHandlerRcptto(session, message, configuration) From ce0d8aae95490454f4c2687b8bbb905664e95798 Mon Sep 17 00:00:00 2001 From: Vladislav Trotsenko Date: Wed, 27 Dec 2023 11:57:55 +0100 Subject: [PATCH 4/4] Technical/Update documentation (#163) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 97a078f..e833502 100644 --- a/README.md +++ b/README.md @@ -449,8 +449,8 @@ Available not configuration `smtpmock` options: | --- | --- | --- | --- | --- | | `1` | `HELO` | no | `domain name`, `localhost`, `ip address`, `[ip address]` | `HELO example.com` | | `1` | `EHLO` | no | `domain name`, `localhost`, `ip address`, `[ip address]` | `EHLO example.com` | -| `2` | `MAIL FROM` | can be used after command with id `1` and greater | `email address`, `` | `MAIL FROM: user@domain.com` | -| `3` | `RCPT TO` | can be used after command with id `2` and greater | `email address`, `` | `RCPT TO: user@domain.com` | +| `2` | `MAIL FROM` | can be used after command with id `1` and greater | `email address`, ``, `localhost email address`, `` | `MAIL FROM: user@domain.com` | +| `3` | `RCPT TO` | can be used after command with id `2` and greater | `email address`, ``, `localhost email address`, `` | `RCPT TO: user@domain.com` | | `4` | `DATA` | can be used after command with id `3` | - | `DATA` | | `5` | `RSET` | can be used after command with id `1` and greater | - | `RSET` | | `6` | `NOOP` | no | - | `NOOP` |