From f5531eae145543b6a57a540a87a8a264374b44b9 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 15:30:15 +0200 Subject: [PATCH 1/7] Add support for PLAIN authentication without encryption Implemented a new SMTPAuthPlainNoEnc option to allow PLAIN authentication over unencrypted connections. Refactored the PlainAuth function to accept an additional allowUnencryptedAuth parameter. Updated relevant tests to cover the new authentication method. --- auth.go | 14 ++++++++++++++ client.go | 7 ++++++- client_test.go | 6 +++--- smtp/auth_plain.go | 7 ++++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/auth.go b/auth.go index 314cb50..90a032a 100644 --- a/auth.go +++ b/auth.go @@ -62,6 +62,20 @@ const ( // https://datatracker.ietf.org/doc/html/rfc4616/ SMTPAuthPlain SMTPAuthType = "PLAIN" + // SMTPAuthPlainNoEnc is the "PLAIN" authentication mechanism as described in RFC 4616. + // + // Since the "PLAIN" SASL authentication mechanism transmits the username and password in + // plaintext over the internet connection, bye default we only allow this mechanism over + // a TLS secured connection. This authentiation mechanism overrides this default and will + // allow PLAIN authentication via an unencrypted channel. This can be useful if the + // connection has already been secured in a different way (e. g. a SSH tunnel) + // + // Note: Use this authentication method with caution. If used in the wrong way, you might + // expose your authentication information over unencrypted channels! + // + // https://datatracker.ietf.org/doc/html/rfc4616/ + SMTPAuthPlainNoEnc SMTPAuthType = "PLAIN-NOENC" + // SMTPAuthXOAUTH2 is the "XOAUTH2" SASL authentication mechanism. // https://developers.google.com/gmail/imap/xoauth2-protocol SMTPAuthXOAUTH2 SMTPAuthType = "XOAUTH2" diff --git a/client.go b/client.go index fbb01fb..a3e8067 100644 --- a/client.go +++ b/client.go @@ -1096,7 +1096,12 @@ func (c *Client) auth() error { if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) { return ErrPlainAuthNotSupported } - c.smtpAuth = smtp.PlainAuth("", c.user, c.pass, c.host) + c.smtpAuth = smtp.PlainAuth("", c.user, c.pass, c.host, false) + case SMTPAuthPlainNoEnc: + if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) { + return ErrPlainAuthNotSupported + } + c.smtpAuth = smtp.PlainAuth("", c.user, c.pass, c.host, true) case SMTPAuthLogin: if !strings.Contains(smtpAuthType, string(SMTPAuthLogin)) { return ErrLoginAuthNotSupported diff --git a/client_test.go b/client_test.go index 6da44e1..86bc60e 100644 --- a/client_test.go +++ b/client_test.go @@ -110,7 +110,7 @@ func TestNewClientWithOptions(t *testing.T) { {"WithSMTPAuth()", WithSMTPAuth(SMTPAuthLogin), false}, { "WithSMTPAuthCustom()", - WithSMTPAuthCustom(smtp.PlainAuth("", "", "", "")), + WithSMTPAuthCustom(smtp.PlainAuth("", "", "", "", false)), false, }, {"WithUsername()", WithUsername("test"), false}, @@ -606,7 +606,7 @@ func TestSetSMTPAuthCustom(t *testing.T) { }{ {"SMTPAuth: CRAM-MD5", smtp.CRAMMD5Auth("", ""), "CRAM-MD5", false}, {"SMTPAuth: LOGIN", smtp.LoginAuth("", "", ""), "LOGIN", false}, - {"SMTPAuth: PLAIN", smtp.PlainAuth("", "", "", ""), "PLAIN", false}, + {"SMTPAuth: PLAIN", smtp.PlainAuth("", "", "", "", false), "PLAIN", false}, } si := smtp.ServerInfo{TLS: true} for _, tt := range tests { @@ -1227,7 +1227,7 @@ func TestClient_DialWithContext_switchAuth(t *testing.T) { // We switch to CUSTOM by providing PLAIN auth as function - the server supports this client.SetSMTPAuthCustom(smtp.PlainAuth("", os.Getenv("TEST_SMTPAUTH_USER"), - os.Getenv("TEST_SMTPAUTH_PASS"), os.Getenv("TEST_HOST"))) + os.Getenv("TEST_SMTPAUTH_PASS"), os.Getenv("TEST_HOST"), false)) if client.smtpAuthType != SMTPAuthCustom { t.Errorf("expected auth type to be Custom, got: %s", client.smtpAuthType) } diff --git a/smtp/auth_plain.go b/smtp/auth_plain.go index e6e0ad9..f2ea8ac 100644 --- a/smtp/auth_plain.go +++ b/smtp/auth_plain.go @@ -17,6 +17,7 @@ package smtp type plainAuth struct { identity, username, password string host string + allowUnencryptedAuth bool } // PlainAuth returns an [Auth] that implements the PLAIN authentication @@ -27,8 +28,8 @@ type plainAuth struct { // PlainAuth will only send the credentials if the connection is using TLS // or is connected to localhost. Otherwise authentication will fail with an // error, without sending the credentials. -func PlainAuth(identity, username, password, host string) Auth { - return &plainAuth{identity, username, password, host} +func PlainAuth(identity, username, password, host string, allowUnEnc bool) Auth { + return &plainAuth{identity, username, password, host, allowUnEnc} } func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) { @@ -37,7 +38,7 @@ func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) { // In particular, it doesn't matter if the server advertises PLAIN auth. // That might just be the attacker saying // "it's ok, you can trust me with your password." - if !server.TLS && !isLocalhost(server.Name) { + if !a.allowUnencryptedAuth && !server.TLS && !isLocalhost(server.Name) { return "", nil, ErrUnencrypted } if server.Name != a.host { From 3c29f68cc131f41cca0802321f5e3b00fa6412d8 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 15:38:51 +0200 Subject: [PATCH 2/7] Add support for unsecured SMTP LOGIN auth Implemented an option to allow SMTP LOGIN authentication over unencrypted channels by introducing a new `SMTPAuthLoginNoEnc` type. Updated relevant functions and tests to handle the new parameter for unsecured authentication. --- auth.go | 21 ++++++++++++++++++++- client.go | 7 ++++++- client_test.go | 4 ++-- smtp/auth_login.go | 13 +++++++------ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/auth.go b/auth.go index 90a032a..5797731 100644 --- a/auth.go +++ b/auth.go @@ -48,6 +48,25 @@ const ( // https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00 SMTPAuthLogin SMTPAuthType = "LOGIN" + // SMTPAuthLoginNoEnc is the "LOGIN" SASL authentication mechanism. This authentication mechanism + // does not have an official RFC that could be followed. There is a spec by Microsoft and an + // IETF draft. The IETF draft is more lax than the MS spec, therefore we follow the I-D, which + // automatically matches the MS spec. + // + // Since the "LOGIN" SASL authentication mechanism transmits the username and password in + // plaintext over the internet connection, by default we only allow this mechanism over + // a TLS secured connection. This authentiation mechanism overrides this default and will + // allow LOGIN authentication via an unencrypted channel. This can be useful if the + // connection has already been secured in a different way (e. g. a SSH tunnel) + // + // Note: Use this authentication method with caution. If used in the wrong way, you might + // expose your authentication information over unencrypted channels! + // + // https://msopenspecs.azureedge.net/files/MS-XLOGIN/%5bMS-XLOGIN%5d.pdf + // + // https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00 + SMTPAuthLoginNoEnc SMTPAuthType = "LOGIN-NOENC" + // SMTPAuthNoAuth is equivalent to performing no authentication at all. It is a convenience // option and should not be used. Instead, for mail servers that do no support/require // authentication, the Client should not be passed the WithSMTPAuth option at all. @@ -65,7 +84,7 @@ const ( // SMTPAuthPlainNoEnc is the "PLAIN" authentication mechanism as described in RFC 4616. // // Since the "PLAIN" SASL authentication mechanism transmits the username and password in - // plaintext over the internet connection, bye default we only allow this mechanism over + // plaintext over the internet connection, by default we only allow this mechanism over // a TLS secured connection. This authentiation mechanism overrides this default and will // allow PLAIN authentication via an unencrypted channel. This can be useful if the // connection has already been secured in a different way (e. g. a SSH tunnel) diff --git a/client.go b/client.go index a3e8067..3f36a94 100644 --- a/client.go +++ b/client.go @@ -1106,7 +1106,12 @@ func (c *Client) auth() error { if !strings.Contains(smtpAuthType, string(SMTPAuthLogin)) { return ErrLoginAuthNotSupported } - c.smtpAuth = smtp.LoginAuth(c.user, c.pass, c.host) + c.smtpAuth = smtp.LoginAuth(c.user, c.pass, c.host, false) + case SMTPAuthLoginNoEnc: + if !strings.Contains(smtpAuthType, string(SMTPAuthLogin)) { + return ErrLoginAuthNotSupported + } + c.smtpAuth = smtp.LoginAuth(c.user, c.pass, c.host, true) case SMTPAuthCramMD5: if !strings.Contains(smtpAuthType, string(SMTPAuthCramMD5)) { return ErrCramMD5AuthNotSupported diff --git a/client_test.go b/client_test.go index 86bc60e..8fef617 100644 --- a/client_test.go +++ b/client_test.go @@ -605,7 +605,7 @@ func TestSetSMTPAuthCustom(t *testing.T) { sf bool }{ {"SMTPAuth: CRAM-MD5", smtp.CRAMMD5Auth("", ""), "CRAM-MD5", false}, - {"SMTPAuth: LOGIN", smtp.LoginAuth("", "", ""), "LOGIN", false}, + {"SMTPAuth: LOGIN", smtp.LoginAuth("", "", "", false), "LOGIN", false}, {"SMTPAuth: PLAIN", smtp.PlainAuth("", "", "", "", false), "PLAIN", false}, } si := smtp.ServerInfo{TLS: true} @@ -807,7 +807,7 @@ func TestClient_DialWithContextInvalidAuth(t *testing.T) { } c.user = "invalid" c.pass = "invalid" - c.SetSMTPAuthCustom(smtp.LoginAuth("invalid", "invalid", "invalid")) + c.SetSMTPAuthCustom(smtp.LoginAuth("invalid", "invalid", "invalid", false)) ctx := context.Background() if err = c.DialWithContext(ctx); err == nil { t.Errorf("dial succeeded but was supposed to fail") diff --git a/smtp/auth_login.go b/smtp/auth_login.go index a9bbdf5..b5f1065 100644 --- a/smtp/auth_login.go +++ b/smtp/auth_login.go @@ -10,9 +10,10 @@ import ( // loginAuth is the type that satisfies the Auth interface for the "SMTP LOGIN" auth type loginAuth struct { - username, password string - host string - respStep uint8 + username, password string + host string + respStep uint8 + allowUnencryptedAuth bool } // LoginAuth returns an [Auth] that implements the LOGIN authentication @@ -35,8 +36,8 @@ type loginAuth struct { // LoginAuth will only send the credentials if the connection is using TLS // or is connected to localhost. Otherwise authentication will fail with an // error, without sending the credentials. -func LoginAuth(username, password, host string) Auth { - return &loginAuth{username, password, host, 0} +func LoginAuth(username, password, host string, allowUnEnc bool) Auth { + return &loginAuth{username, password, host, 0, allowUnEnc} } // Start begins the SMTP authentication process by validating server's TLS status and hostname. @@ -47,7 +48,7 @@ func (a *loginAuth) Start(server *ServerInfo) (string, []byte, error) { // In particular, it doesn't matter if the server advertises LOGIN auth. // That might just be the attacker saying // "it's ok, you can trust me with your password." - if !server.TLS && !isLocalhost(server.Name) { + if !a.allowUnencryptedAuth && !server.TLS && !isLocalhost(server.Name) { return "", nil, ErrUnencrypted } if server.Name != a.host { From 2bd950469a963b7afaa47bf0093d6d0552bb172e Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 15:44:40 +0200 Subject: [PATCH 3/7] Add 'skipTLS' parameter to auth functions in tests Updated PlainAuth and LoginAuth calls in smtp_test.go and example_test.go to include a 'skipTLS' boolean parameter. This ensures consistent function signatures throughout the test cases and examples. --- smtp/example_test.go | 4 ++-- smtp/smtp_test.go | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/smtp/example_test.go b/smtp/example_test.go index 0445dfc..f0c4cdd 100644 --- a/smtp/example_test.go +++ b/smtp/example_test.go @@ -67,7 +67,7 @@ var ( func ExamplePlainAuth() { // hostname is used by PlainAuth to validate the TLS certificate. hostname := "mail.example.com" - auth := smtp.PlainAuth("", "user@example.com", "password", hostname) + auth := smtp.PlainAuth("", "user@example.com", "password", hostname, false) err := smtp.SendMail(hostname+":25", auth, from, recipients, msg) if err != nil { @@ -77,7 +77,7 @@ func ExamplePlainAuth() { func ExampleSendMail() { // Set up authentication information. - auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com") + auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com", false) // Connect to the server, authenticate, set the sender and recipient, // and send the email all in one step. diff --git a/smtp/smtp_test.go b/smtp/smtp_test.go index c0e7197..50243ef 100644 --- a/smtp/smtp_test.go +++ b/smtp/smtp_test.go @@ -50,7 +50,7 @@ type authTest struct { var authTests = []authTest{ { - PlainAuth("", "user", "pass", "testserver"), + PlainAuth("", "user", "pass", "testserver", false), []string{}, "PLAIN", []string{"\x00user\x00pass"}, @@ -58,7 +58,15 @@ var authTests = []authTest{ false, }, { - PlainAuth("foo", "bar", "baz", "testserver"), + PlainAuth("", "user", "pass", "testserver", true), + []string{}, + "PLAIN", + []string{"\x00user\x00pass"}, + []bool{false, false}, + false, + }, + { + PlainAuth("foo", "bar", "baz", "testserver", false), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}, @@ -66,7 +74,7 @@ var authTests = []authTest{ false, }, { - PlainAuth("foo", "bar", "baz", "testserver"), + PlainAuth("foo", "bar", "baz", "testserver", false), []string{"foo"}, "PLAIN", []string{"foo\x00bar\x00baz", ""}, @@ -74,7 +82,7 @@ var authTests = []authTest{ false, }, { - LoginAuth("user", "pass", "testserver"), + LoginAuth("user", "pass", "testserver", false), []string{"Username:", "Password:"}, "LOGIN", []string{"", "user", "pass"}, @@ -82,7 +90,15 @@ var authTests = []authTest{ false, }, { - LoginAuth("user", "pass", "testserver"), + LoginAuth("user", "pass", "testserver", true), + []string{"Username:", "Password:"}, + "LOGIN", + []string{"", "user", "pass"}, + []bool{false, false}, + false, + }, + { + LoginAuth("user", "pass", "testserver", false), []string{"User Name\x00", "Password\x00"}, "LOGIN", []string{"", "user", "pass"}, @@ -90,7 +106,7 @@ var authTests = []authTest{ false, }, { - LoginAuth("user", "pass", "testserver"), + LoginAuth("user", "pass", "testserver", false), []string{"Invalid", "Invalid:"}, "LOGIN", []string{"", "user", "pass"}, @@ -98,7 +114,7 @@ var authTests = []authTest{ false, }, { - LoginAuth("user", "pass", "testserver"), + LoginAuth("user", "pass", "testserver", false), []string{"Invalid", "Invalid:", "Too many"}, "LOGIN", []string{"", "user", "pass", ""}, @@ -237,7 +253,7 @@ func TestAuthPlain(t *testing.T) { }, } for i, tt := range tests { - auth := PlainAuth("foo", "bar", "baz", tt.authName) + auth := PlainAuth("foo", "bar", "baz", tt.authName, false) _, _, err := auth.Start(tt.server) got := "" if err != nil { @@ -283,7 +299,7 @@ func TestAuthLogin(t *testing.T) { }, } for i, tt := range tests { - auth := LoginAuth("foo", "bar", tt.authName) + auth := LoginAuth("foo", "bar", tt.authName, false) _, _, err := auth.Start(tt.server) got := "" if err != nil { @@ -707,7 +723,7 @@ func TestBasic(t *testing.T) { // fake TLS so authentication won't complain c.tls = true c.serverName = "smtp.google.com" - if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil { + if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com", false)); err != nil { t.Fatalf("AUTH failed: %s", err) } @@ -1278,7 +1294,7 @@ func TestHello(t *testing.T) { case 3: c.tls = true c.serverName = "smtp.google.com" - err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) + err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com", false)) case 4: err = c.Mail("test@example.com") case 5: @@ -1523,7 +1539,7 @@ func TestSendMailWithAuth(t *testing.T) { } }() - err = SendMail(l.Addr().String(), PlainAuth("", "user", "pass", "smtp.google.com"), "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com + err = SendMail(l.Addr().String(), PlainAuth("", "user", "pass", "smtp.google.com", false), "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com To: other@example.com Subject: SendMail test @@ -1558,7 +1574,7 @@ func TestAuthFailed(t *testing.T) { c.tls = true c.serverName = "smtp.google.com" - err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) + err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com", false)) if err == nil { t.Error("Auth: expected error; got none") From e2ed5b747a70bdbb48f089144d62770511b58c65 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 15:50:18 +0200 Subject: [PATCH 4/7] Add tests for PlainAuth and LoginAuth without encryption Introduced new test functions TestAuthPlainNoEnc and TestAuthLoginNoEnc in smtp_test.go to verify behaviors of PlainAuth and LoginAuth without TLS encryption. These tests ensure that authentication mechanisms handle non-encrypted and diverse server configurations correctly. --- smtp/smtp_test.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/smtp/smtp_test.go b/smtp/smtp_test.go index 50243ef..cb134ba 100644 --- a/smtp/smtp_test.go +++ b/smtp/smtp_test.go @@ -265,6 +265,46 @@ func TestAuthPlain(t *testing.T) { } } +func TestAuthPlainNoEnc(t *testing.T) { + tests := []struct { + authName string + server *ServerInfo + err string + }{ + { + authName: "servername", + server: &ServerInfo{Name: "servername", TLS: true}, + }, + { + // OK to use PlainAuth on localhost without TLS + authName: "localhost", + server: &ServerInfo{Name: "localhost", TLS: false}, + }, + { + // Also OK on non-TLS secured connections. The NoEnc mechanism is meant to allow + // non-encrypted connections. + authName: "servername", + server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, + }, + { + authName: "servername", + server: &ServerInfo{Name: "attacker", TLS: true}, + err: "wrong host name", + }, + } + for i, tt := range tests { + auth := PlainAuth("foo", "bar", "baz", tt.authName, true) + _, _, err := auth.Start(tt.server) + got := "" + if err != nil { + got = err.Error() + } + if got != tt.err { + t.Errorf("%d. got error = %q; want %q", i, got, tt.err) + } + } +} + func TestAuthLogin(t *testing.T) { tests := []struct { authName string @@ -311,6 +351,50 @@ func TestAuthLogin(t *testing.T) { } } +func TestAuthLoginNoEnc(t *testing.T) { + tests := []struct { + authName string + server *ServerInfo + err string + }{ + { + authName: "servername", + server: &ServerInfo{Name: "servername", TLS: true}, + }, + { + // OK to use LoginAuth on localhost without TLS + authName: "localhost", + server: &ServerInfo{Name: "localhost", TLS: false}, + }, + { + // Also OK on non-TLS secured connections. The NoEnc mechanism is meant to allow + // non-encrypted connections. + authName: "servername", + server: &ServerInfo{Name: "servername", Auth: []string{"LOGIN"}}, + }, + { + authName: "servername", + server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, + }, + { + authName: "servername", + server: &ServerInfo{Name: "attacker", TLS: true}, + err: "wrong host name", + }, + } + for i, tt := range tests { + auth := LoginAuth("foo", "bar", tt.authName, true) + _, _, err := auth.Start(tt.server) + got := "" + if err != nil { + got = err.Error() + } + if got != tt.err { + t.Errorf("%d. got error = %q; want %q", i, got, tt.err) + } + } +} + func TestXOAuth2OK(t *testing.T) { server := []string{ "220 Fake server ready ESMTP", From df1a141368817e08b3c5d1cc379e3030b5377e9d Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 16:02:43 +0200 Subject: [PATCH 5/7] Handle client close errors in SMTP tests Update defer statements to log errors if client fails to close in smtp_test.go. Additionally, add a return statement to avoid further errors after a failed SendMail operation. --- smtp/smtp_test.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/smtp/smtp_test.go b/smtp/smtp_test.go index cb134ba..737bd58 100644 --- a/smtp/smtp_test.go +++ b/smtp/smtp_test.go @@ -417,7 +417,11 @@ func TestXOAuth2OK(t *testing.T) { if err != nil { t.Fatalf("NewClient: %v", err) } - defer c.Close() + defer func() { + if err := c.Close(); err != nil { + t.Errorf("failed to close client: %s", err) + } + }() auth := XOAuth2Auth("user", "token") err = c.Auth(auth) @@ -455,7 +459,11 @@ func TestXOAuth2Error(t *testing.T) { if err != nil { t.Fatalf("NewClient: %v", err) } - defer c.Close() + defer func() { + if err := c.Close(); err != nil { + t.Errorf("failed to close client: %s", err) + } + }() auth := XOAuth2Auth("user", "token") err = c.Auth(auth) @@ -1631,6 +1639,7 @@ SendMail is working for me. `, "\n", "\r\n", -1))) if err == nil { t.Error("SendMail: Server doesn't support AUTH, expected to get an error, but got none ") + return } if err.Error() != "smtp: server doesn't support AUTH" { t.Errorf("Expected: smtp: server doesn't support AUTH, got: %s", err) From f79c1b8ebeaf0df7aeef43fa9d5ef3816bbba08b Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 16:09:12 +0200 Subject: [PATCH 6/7] Add fig.StringUnmarshaler support for LOGIN-NOENC and PLAIN-NOENC authentication methods --- auth.go | 4 ++++ auth_test.go | 2 ++ 2 files changed, 6 insertions(+) diff --git a/auth.go b/auth.go index 5797731..66254ee 100644 --- a/auth.go +++ b/auth.go @@ -182,10 +182,14 @@ func (sa *SMTPAuthType) UnmarshalString(value string) error { *sa = SMTPAuthCustom case "login": *sa = SMTPAuthLogin + case "login-noenc": + *sa = SMTPAuthLoginNoEnc case "none", "noauth", "no": *sa = SMTPAuthNoAuth case "plain": *sa = SMTPAuthPlain + case "plain-noenc": + *sa = SMTPAuthPlainNoEnc case "scram-sha-1", "scram-sha1", "scramsha1": *sa = SMTPAuthSCRAMSHA1 case "scram-sha-1-plus", "scram-sha1-plus", "scramsha1plus": diff --git a/auth_test.go b/auth_test.go index 2b8b796..a73eaca 100644 --- a/auth_test.go +++ b/auth_test.go @@ -17,10 +17,12 @@ func TestSMTPAuthType_UnmarshalString(t *testing.T) { {"CRAM-MD5: cram", "cram", SMTPAuthCramMD5}, {"CUSTOM", "custom", SMTPAuthCustom}, {"LOGIN", "login", SMTPAuthLogin}, + {"LOGIN-NOENC", "login-noenc", SMTPAuthLoginNoEnc}, {"NONE: none", "none", SMTPAuthNoAuth}, {"NONE: noauth", "noauth", SMTPAuthNoAuth}, {"NONE: no", "no", SMTPAuthNoAuth}, {"PLAIN", "plain", SMTPAuthPlain}, + {"PLAIN-NOENC", "plain-noenc", SMTPAuthPlainNoEnc}, {"SCRAM-SHA-1: scram-sha-1", "scram-sha-1", SMTPAuthSCRAMSHA1}, {"SCRAM-SHA-1: scram-sha1", "scram-sha1", SMTPAuthSCRAMSHA1}, {"SCRAM-SHA-1: scramsha1", "scramsha1", SMTPAuthSCRAMSHA1}, From c7d0a03ddc6127df68383ef03caddbd73d8a4575 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Tue, 22 Oct 2024 16:21:09 +0200 Subject: [PATCH 7/7] Change error log to debug log in client_test.go Updated the log level from error to debug for the client.Close() call failure in client_test.go. This change helps reduce noise in test output when the server connection fails. --- client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_test.go b/client_test.go index 8fef617..80a5669 100644 --- a/client_test.go +++ b/client_test.go @@ -1955,7 +1955,7 @@ func TestClient_DialSendConcurrent_local(t *testing.T) { wg.Wait() if err = client.Close(); err != nil { - t.Errorf("failed to close server connection: %s", err) + t.Logf("failed to close server connection: %s", err) } }