@@ -53,7 +53,8 @@ type SMTPHandler struct {
53
53
cfg codersdk.NotificationsEmailConfig
54
54
log slog.Logger
55
55
56
- loginWarnOnce sync.Once
56
+ noAuthWarnOnce sync.Once
57
+ loginWarnOnce sync.Once
57
58
58
59
helpers template.FuncMap
59
60
}
@@ -136,14 +137,20 @@ func (s *SMTPHandler) dispatch(subject, htmlBody, plainBody, to string) Delivery
136
137
137
138
// Check for authentication capabilities.
138
139
if ok , avail := c .Extension ("AUTH" ); ok {
139
- // Ensure the auth mechanisms available are ones we can use.
140
+ // Ensure the auth mechanisms available are ones we can use, and create a SASL client .
140
141
auth , err := s .auth (ctx , avail )
141
142
if err != nil {
142
143
return true , xerrors .Errorf ("determine auth mechanism: %w" , err )
143
144
}
144
145
145
- // If so, use the auth mechanism to authenticate.
146
- if auth != nil {
146
+ if auth == nil {
147
+ // If we get here, no SASL client (which handles authentication) was returned.
148
+ // This is expected if auth is supported by the smarthost BUT no authentication details were configured.
149
+ s .noAuthWarnOnce .Do (func () {
150
+ s .log .Warn (ctx , "skipping auth; no authentication client created" )
151
+ })
152
+ } else {
153
+ // We have a SASL client, use it to authenticate.
147
154
if err := c .Auth (auth ); err != nil {
148
155
return true , xerrors .Errorf ("%T auth: %w" , auth , err )
149
156
}
@@ -431,6 +438,12 @@ func (s *SMTPHandler) loadCertificate() (*tls.Certificate, error) {
431
438
func (s * SMTPHandler ) auth (ctx context.Context , mechs string ) (sasl.Client , error ) {
432
439
username := s .cfg .Auth .Username .String ()
433
440
441
+ // All auth mechanisms require username, so if one is not defined then don't return an auth client.
442
+ if username == "" {
443
+ // nolint:nilnil // This is a valid response.
444
+ return nil , nil
445
+ }
446
+
434
447
var errs error
435
448
list := strings .Split (mechs , " " )
436
449
for _ , mech := range list {
0 commit comments