github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/pkg/ev/evsmtp/send_mail.go (about) 1 package evsmtp 2 3 import ( 4 "context" 5 "crypto/tls" 6 "errors" 7 "github.com/go-email-validator/go-email-validator/pkg/ev/evsmtp/smtpclient" 8 "io" 9 "net/smtp" 10 "sync" 11 ) 12 13 // SendMailStage is stage type of SendMail 14 type SendMailStage uint8 15 16 // SafeSendMailStage is thread safe SendMailStage 17 type SafeSendMailStage struct { 18 SendMailStage 19 mu sync.RWMutex 20 } 21 22 // Set sets stage 23 func (s *SafeSendMailStage) Set(val SendMailStage) { 24 s.mu.Lock() 25 defer s.mu.Unlock() 26 s.SendMailStage = val 27 } 28 29 // Get returns stage 30 func (s *SafeSendMailStage) Get() SendMailStage { 31 s.mu.RLock() 32 defer s.mu.RUnlock() 33 return s.SendMailStage 34 } 35 36 // Constants of stages 37 const ( 38 ClientStage SendMailStage = iota + 1 39 HelloStage 40 AuthStage 41 MailStage 42 RCPTsStage 43 QuitStage 44 CloseStage 45 ) 46 47 // SendMail is interface of custom realization as smtp.SendMail 48 type SendMail interface { 49 Client() smtpclient.SMTPClient 50 Hello(helloName string) error 51 Auth(a smtp.Auth) error 52 Mail(from string) error 53 RCPTs(addrs []string) map[string]error 54 Data() (io.WriteCloser, error) 55 Write(w io.WriteCloser, msg []byte) error 56 Quit() error 57 Close() error 58 } 59 60 var testHookStartTLS func(*tls.Config) 61 62 // SendMailDialerFactory is factory for SendMail with dialing 63 type SendMailDialerFactory func(ctx context.Context, host string, opts Options) (SendMail, error) 64 65 // NewSendMailFactory creates SendMailDialerFactory 66 func NewSendMailFactory(dialFunc DialFunc, tlsConfig *tls.Config) SendMailDialerFactory { 67 return NewSendMailCustom(dialFunc, tlsConfig, NewSendMail) 68 } 69 70 // SendMailFactory is factory for SendMail 71 type SendMailFactory func(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail 72 73 // NewSendMailCustom creates SendMailFactory with dialing and customization calling of SendMailFactory 74 func NewSendMailCustom(dialFunc DialFunc, tlsConfig *tls.Config, factory SendMailFactory) SendMailDialerFactory { 75 return func(ctx context.Context, host string, opts Options) (SendMail, error) { 76 conn, err := dialFunc(ctx, host, opts.Proxy()) 77 if err != nil { 78 return nil, err 79 } 80 81 return factory(conn, tlsConfig), nil 82 } 83 } 84 85 // NewSendMail instantiates SendMail 86 func NewSendMail(client smtpclient.SMTPClient, tlsConfig *tls.Config) SendMail { 87 return &sendMail{ 88 client: client, 89 tlsConfig: tlsConfig, 90 } 91 } 92 93 type sendMail struct { 94 client smtpclient.SMTPClient 95 tlsConfig *tls.Config 96 } 97 98 func (s *sendMail) Client() smtpclient.SMTPClient { 99 return s.client 100 } 101 102 func (s *sendMail) Hello(helloName string) error { 103 return s.client.Hello(helloName) 104 } 105 106 func (s *sendMail) Auth(a smtp.Auth) error { 107 if ok, _ := s.client.Extension("STARTTLS"); ok && s.tlsConfig != nil { 108 if testHookStartTLS != nil { 109 testHookStartTLS(s.tlsConfig) 110 } 111 if err := s.client.StartTLS(s.tlsConfig); err != nil { 112 return err 113 } 114 } 115 116 if a != nil { 117 if ok, _ := s.client.Extension("AUTH"); !ok { 118 return errors.New("smtp_checker: server doesn't support AUTH") 119 } 120 if err := s.client.Auth(a); err != nil { 121 return err 122 } 123 } 124 return nil 125 } 126 127 func (s *sendMail) Mail(from string) error { 128 return s.client.Mail(from) 129 } 130 131 func (s *sendMail) RCPTs(addrs []string) map[string]error { 132 errs := make(map[string]error) 133 134 for _, addr := range addrs { 135 if err := s.client.Rcpt(addr); err != nil { 136 errs[addr] = err 137 } 138 } 139 140 return errs 141 } 142 143 func (s *sendMail) Data() (io.WriteCloser, error) { 144 return s.client.Data() 145 } 146 147 func (s *sendMail) Write(w io.WriteCloser, msg []byte) error { 148 if _, err := w.Write(msg); err != nil { 149 return err 150 } 151 152 return w.Close() 153 } 154 155 func (s *sendMail) Quit() error { 156 return s.client.Quit() 157 } 158 159 func (s *sendMail) Close() error { 160 return s.client.Close() 161 }