1package service23import (4 "fmt"56 _ "github.com/emersion/go-message/charset"7 "github.com/emersion/go-message/textproto"8 "github.com/emersion/go-sasl"9 smtp "github.com/emersion/go-smtp"10)1112const (13 CONNTYPE_PLAIN = "plain"14 CONNTYPE_STARTTLS = "starttls"15 CONNTYPE_TLS = "tls"16)1718type MTA interface {19 Send(header textproto.Header, body []byte, sender string, rcpts []string) error20}21type MockMTA func(header textproto.Header, body []byte, sender string, rcpts []string) error2223func (mta *MockMTA) Send(header textproto.Header, body []byte, sender string, rcpts []string) error {24 return (func(header textproto.Header, body []byte, sender string, rcpts []string) error)(*mta)(header, body, sender, rcpts)25}2627type SMTPClient struct {28 Address string29 AuthClient sasl.Client30 ConnType string31}3233func (mta *SMTPClient) Send(header textproto.Header, body []byte, sender string, rcpts []string) error {34 var (35 c *smtp.Client36 err error37 )38 switch mta.ConnType {39 case CONNTYPE_PLAIN:40 c, err = smtp.Dial(mta.Address)41 case CONNTYPE_STARTTLS:42 c, err = smtp.DialStartTLS(mta.Address, nil)43 case CONNTYPE_TLS:44 c, err = smtp.DialTLS(mta.Address, nil)45 default:46 return fmt.Errorf("unsupport smtp connection type")47 }48 if err != nil {49 return err50 }51 defer c.Close()5253 if mta.AuthClient != nil {54 if ok, _ := c.Extension("AUTH"); !ok {55 return fmt.Errorf("smtp server %s doesn't support AUTH", mta.Address)56 }57 if err := c.Auth(mta.AuthClient); err != nil {58 return err59 }60 }6162 if err := c.Mail(sender, nil); err != nil {63 return err64 }6566 for _, rcpt := range rcpts {67 if err := c.Rcpt(rcpt, nil); err != nil {68 return err69 }70 }7172 wc, err := c.Data()73 if err != nil {74 return fmt.Errorf("mail DATA cmd error: %v", err)75 }7677 if err := textproto.WriteHeader(wc, header); err != nil {78 wc.Close()79 return fmt.Errorf("send mail header error: %v", err)80 }81 if _, err := wc.Write(body); err != nil {82 wc.Close()83 return fmt.Errorf("send mail body error: %v", err)84 }8586 if err := wc.Close(); err != nil {87 return fmt.Errorf("mail data writer close error: %v", err)88 }89 return c.Quit()90}