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  }