11package notifications
22
33import (
4+ "context"
45 "crypto/tls"
56 "fmt"
67 "io"
8+ "net"
79 "net/smtp"
10+ "strconv"
811 "sync"
12+ "time"
13+ )
14+
15+ const (
16+ // dialerTimeout defines the timeout for establishing SMTP connections.
17+ dialerTimeout = 5 * time .Second
918)
1019
1120type mailer interface {
@@ -45,7 +54,7 @@ func NewEmailNotifier(cfg EmailConfig, templates *TemplateHandler) *EmailNotifie
4554 return n
4655}
4756
48- func (e * EmailNotifier ) ensureConnected () error {
57+ func (e * EmailNotifier ) ensureConnected (ctx context. Context ) error {
4958 e .clientMux .Lock ()
5059 defer e .clientMux .Unlock ()
5160
@@ -58,7 +67,7 @@ func (e *EmailNotifier) ensureConnected() error {
5867 _ = e .client .Close ()
5968 }
6069
61- client , err := createSMTPClient (e .server , e .port , e .username , e .password )
70+ client , err := createSMTPClient (ctx , e .server , e .port , e .username , e .password )
6271 if err != nil {
6372 return fmt .Errorf ("failed to reconnect SMTP client: %w" , err )
6473 }
@@ -68,9 +77,9 @@ func (e *EmailNotifier) ensureConnected() error {
6877 return nil
6978}
7079
71- func (e * EmailNotifier ) Send (event Event ) error {
80+ func (e * EmailNotifier ) Send (ctx context. Context , event Event ) error {
7281 // Ensure we have a valid connection
73- if err := e .ensureConnected (); err != nil {
82+ if err := e .ensureConnected (ctx ); err != nil {
7483 return fmt .Errorf ("failed to ensure SMTP connection: %w" , err )
7584 }
7685
@@ -114,12 +123,21 @@ func (e *EmailNotifier) Send(event Event) error {
114123 return nil
115124}
116125
117- func createSMTPClient (host string , port int , username , password string ) (* smtp.Client , error ) {
118- addr := fmt .Sprintf ("%s:%d" , host , port )
126+ func createSMTPClient (ctx context.Context , host string , port int , username , password string ) (* smtp.Client , error ) {
127+ addr := net .JoinHostPort (host , strconv .Itoa (port ))
128+
129+ dialer := & net.Dialer {
130+ Timeout : dialerTimeout ,
131+ }
132+
133+ conn , err := dialer .DialContext (ctx , "tcp" , addr )
134+ if err != nil {
135+ return nil , fmt .Errorf ("dial SMTP server: %w" , err )
136+ }
119137
120- client , err := smtp .Dial ( addr )
138+ client , err := smtp .NewClient ( conn , host )
121139 if err != nil {
122- return nil , fmt .Errorf ("failed to dial SMTP server : %w" , err )
140+ return nil , fmt .Errorf ("create SMTP client : %w" , err )
123141 }
124142
125143 tlsConfig := & tls.Config {
0 commit comments