Repository: nhost/hasura-auth

Issue:
Outlook SMTP support
Outlook SMTP does not support PLAIN auth method. Is it possible to return support of LOGIN method or add XOAUTH2 ?

https://support.microsoft.com/en-us/office/outlook-com-no-longer-supports-auth-plain-authentication-07f7d5e9-1697-465f-84d2-4513d4ff0145


Hints from issue comments:
@dbarrosop: Adding support for LOGIN should be fairly easy, I can give you a beta image to test soon.@dbarrosop: Would you mind testing the version 0.37.2-beta1 and letting us know if it works?@ooppsss60: It works, thanks.@dbarrosop: Thanks for confirming, next release should have the fix.

Solution patch:
diff --git a/go/cmd/email.go b/go/cmd/email.go
index 467455a9..e30f8901 100644
--- a/go/cmd/email.go
+++ b/go/cmd/email.go
@@ -49,8 +49,7 @@ func getSMTPEmailer(cCtx *cli.Context, logger *slog.Logger) (*notifications.Emai
 	var auth smtp.Auth
 	switch GetEnumValue(cCtx, flagSMTPAuthMethod) {
 	case "LOGIN":
-		logger.Warn("SMTP auth LOGIN method is deprecated, using PLAIN instead")
-		auth = notifications.PlainAuth("", user, password, host)
+		auth = notifications.LoginAuth(user, password, host)
 	case "PLAIN":
 		auth = notifications.PlainAuth("", user, password, host)
 	case "CRAM-MD5":
diff --git a/go/notifications/smtp_login.go b/go/notifications/smtp_login.go
new file mode 100644
index 00000000..e38370fd
--- /dev/null
+++ b/go/notifications/smtp_login.go
@@ -0,0 +1,42 @@
+package notifications
+
+import (
+	"errors"
+	"net/smtp"
+)
+
+type loginAuth struct {
+	username, password string
+	host               string
+}
+
+func LoginAuth(username, password, host string) smtp.Auth {
+	return &loginAuth{username, password, host}
+}
+
+func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
+	// Same security checks as PLAIN auth
+	if !server.TLS && !isLocalhost(server.Name) {
+		return "", nil, errors.New("unencrypted connection") //nolint:goerr113
+	}
+	if server.Name != a.host {
+		return "", nil, errors.New("wrong host name") //nolint:goerr113
+	}
+
+	return "LOGIN", nil, nil
+}
+
+func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
+	if !more {
+		return nil, nil
+	}
+
+	switch string(fromServer) {
+	case "Username:", "User Name:", "Username", "User:": // various forms servers might use
+		return []byte(a.username), nil
+	case "Password:", "Password": // various forms servers might use
+		return []byte(a.password), nil
+	default:
+		return nil, errors.New("unexpected server challenge") //nolint:goerr113
+	}
+}



Test patch:
diff --git a/go/notifications/smtp_login_test.go b/go/notifications/smtp_login_test.go
new file mode 100644
index 00000000..b4009226
--- /dev/null
+++ b/go/notifications/smtp_login_test.go
@@ -0,0 +1,49 @@
+package notifications_test
+
+import (
+	"testing"
+
+	"github.com/nhost/hasura-auth/go/notifications"
+)
+
+func TestSMTPAuthLogin(t *testing.T) {
+	t.Parallel()
+
+	cases := []struct {
+		name     string
+		user     string
+		password string
+		host     string
+	}{
+		{
+			name:     "success",
+			user:     "user",
+			password: "password",
+			host:     "localhost",
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+
+			mail := notifications.NewEmail(
+				"localhost",
+				1025,
+				false,
+				notifications.LoginAuth(tc.user, tc.password, tc.host),
+				"admin@localhost",
+				map[string]string{
+					"x-something": "asd",
+				},
+				nil,
+			)
+			headers := map[string]string{
+				"x-another": "qwe",
+			}
+			if err := mail.Send("user@localhost", "some email", "contents", headers); err != nil {
+				t.Fatalf("error sending email: %v", err)
+			}
+		})
+	}
+}