diff --git a/coderd/notifications/dispatch/smtp.go b/coderd/notifications/dispatch/smtp.go index 107e9e2e8c723..b03108e95cc72 100644 --- a/coderd/notifications/dispatch/smtp.go +++ b/coderd/notifications/dispatch/smtp.go @@ -53,7 +53,8 @@ type SMTPHandler struct { cfg codersdk.NotificationsEmailConfig log slog.Logger - loginWarnOnce sync.Once + noAuthWarnOnce sync.Once + loginWarnOnce sync.Once helpers template.FuncMap } @@ -136,14 +137,20 @@ func (s *SMTPHandler) dispatch(subject, htmlBody, plainBody, to string) Delivery // Check for authentication capabilities. if ok, avail := c.Extension("AUTH"); ok { - // Ensure the auth mechanisms available are ones we can use. + // Ensure the auth mechanisms available are ones we can use, and create a SASL client. auth, err := s.auth(ctx, avail) if err != nil { return true, xerrors.Errorf("determine auth mechanism: %w", err) } - // If so, use the auth mechanism to authenticate. - if auth != nil { + if auth == nil { + // If we get here, no SASL client (which handles authentication) was returned. + // This is expected if auth is supported by the smarthost BUT no authentication details were configured. + s.noAuthWarnOnce.Do(func() { + s.log.Warn(ctx, "skipping auth; no authentication client created") + }) + } else { + // We have a SASL client, use it to authenticate. if err := c.Auth(auth); err != nil { return true, xerrors.Errorf("%T auth: %w", auth, err) } @@ -431,6 +438,12 @@ func (s *SMTPHandler) loadCertificate() (*tls.Certificate, error) { func (s *SMTPHandler) auth(ctx context.Context, mechs string) (sasl.Client, error) { username := s.cfg.Auth.Username.String() + // All auth mechanisms require username, so if one is not defined then don't return an auth client. + if username == "" { + // nolint:nilnil // This is a valid response. + return nil, nil + } + var errs error list := strings.Split(mechs, " ") for _, mech := range list { diff --git a/coderd/notifications/dispatch/smtp_test.go b/coderd/notifications/dispatch/smtp_test.go index 7576c4c936fa4..eb12f05ad46c7 100644 --- a/coderd/notifications/dispatch/smtp_test.go +++ b/coderd/notifications/dispatch/smtp_test.go @@ -203,7 +203,6 @@ func TestSMTP(t *testing.T) { retryable: false, }, { - // No auth, no problem! name: "No auth mechanisms supported, none configured", authMechs: []string{}, cfg: codersdk.NotificationsEmailConfig{ @@ -213,6 +212,16 @@ func TestSMTP(t *testing.T) { toAddrs: []string{to}, expectedAuthMeth: "", }, + { + name: "Auth mechanisms supported optionally, none configured", + authMechs: []string{sasl.Login, sasl.Plain}, + cfg: codersdk.NotificationsEmailConfig{ + Hello: hello, + From: from, + }, + toAddrs: []string{to}, + expectedAuthMeth: "", + }, /** * TLS connections */