MCPcopy Index your code
hub / github.com/coder/coder / dispatch

Method dispatch

coderd/notifications/dispatch/smtp.go:99–272  ·  view source on GitHub ↗

dispatch returns a DeliveryFunc capable of delivering a notification via SMTP. Our requirements are too complex to be implemented using smtp.SendMail: - we require custom TLS settings - dynamic determination of available AUTH mechanisms NOTE: this is inspired by Alertmanager's email notifier: http

(subject, htmlBody, plainBody, to string)

Source from the content-addressed store, hash-verified

97// NOTE: this is inspired by Alertmanager's email notifier:
98// https://github.com/prometheus/alertmanager/blob/342f6a599ce16c138663f18ed0b880e777c3017d/notify/email/email.go
99func (s *SMTPHandler) dispatch(subject, htmlBody, plainBody, to string) DeliveryFunc {
100 return func(ctx context.Context, msgID uuid.UUID) (bool, error) {
101 select {
102 case <-ctx.Done():
103 return false, ctx.Err()
104 default:
105 }
106
107 s.log.Debug(ctx, "dispatching via SMTP", slog.F("msg_id", msgID))
108
109 // Dial the smarthost to establish a connection.
110 smarthost, smarthostPort, err := s.smarthost()
111 if err != nil {
112 return false, xerrors.Errorf("'smarthost' validation: %w", err)
113 }
114
115 // Outer context has a deadline (see CODER_NOTIFICATIONS_DISPATCH_TIMEOUT).
116 if _, ok := ctx.Deadline(); !ok {
117 return false, xerrors.Errorf("context has no deadline")
118 }
119
120 // TODO: reuse client across dispatches (if possible).
121 // Create an SMTP client for communication with the smarthost.
122 c, err := s.client(ctx, smarthost, smarthostPort)
123 if err != nil {
124 return true, xerrors.Errorf("SMTP client creation: %w", err)
125 }
126
127 // Cleanup.
128 defer func() {
129 if err := c.Quit(); err != nil {
130 s.log.Warn(ctx, "failed to close SMTP connection", slog.Error(err))
131 }
132 }()
133
134 // Check for authentication capabilities.
135 if ok, avail := c.Extension("AUTH"); ok {
136 // Ensure the auth mechanisms available are ones we can use, and create a SASL client.
137 auth, err := s.auth(ctx, avail)
138 if err != nil {
139 return true, xerrors.Errorf("determine auth mechanism: %w", err)
140 }
141
142 if auth == nil {
143 // If we get here, no SASL client (which handles authentication) was returned.
144 // This is expected if auth is supported by the smarthost BUT no authentication details were configured.
145 s.noAuthWarnOnce.Do(func() {
146 s.log.Warn(ctx, "skipping auth; no authentication client created")
147 })
148 } else {
149 // We have a SASL client, use it to authenticate.
150 if err := c.Auth(auth); err != nil {
151 return true, xerrors.Errorf("%T auth: %w", auth, err)
152 }
153 }
154 } else if !s.cfg.Auth.Empty() {
155 return false, xerrors.New("no authentication mechanisms supported by server")
156 }

Callers 1

DispatcherMethod · 0.95

Calls 15

smarthostMethod · 0.95
clientMethod · 0.95
authMethod · 0.95
validateFromAddrMethod · 0.95
validateToAddrsMethod · 0.95
hostnameMethod · 0.95
ErrMethod · 0.80
AuthMethod · 0.80
MailMethod · 0.80
RcptMethod · 0.80
DataMethod · 0.80
DoMethod · 0.65

Tested by

no test coverage detected