package mail import ( "crypto/tls" "github.com/pkg/errors" gomail "gopkg.in/mail.v2" ) type SendFunc func(*SendOption) type SendOption struct { Charset string AddressHeaders []AddressHeader Headers []Header Body Body AlternativeBodies []Body } type AddressHeader struct { Field string Address string Name string } type Header struct { Field string Values []string } type Body struct { Type string Content string PartSetting gomail.PartSetting } func WithCharset(charset string) func(*SendOption) { return func(opt *SendOption) { opt.Charset = charset } } func WithSender(address string, name string) func(*SendOption) { return WithAddressHeader("From", address, name) } func WithSubject(subject string) func(*SendOption) { return WithHeader("Subject", subject) } func WithAddressHeader(field, address, name string) func(*SendOption) { return func(opt *SendOption) { opt.AddressHeaders = append(opt.AddressHeaders, AddressHeader{field, address, name}) } } func WithHeader(field string, values ...string) func(*SendOption) { return func(opt *SendOption) { opt.Headers = append(opt.Headers, Header{field, values}) } } func WithRecipients(addresses ...string) func(*SendOption) { return WithHeader("To", addresses...) } func WithCopies(addresses ...string) func(*SendOption) { return WithHeader("Cc", addresses...) } func WithInvisibleCopies(addresses ...string) func(*SendOption) { return WithHeader("Cci", addresses...) } func WithBody(contentType string, content string, setting gomail.PartSetting) func(*SendOption) { return func(opt *SendOption) { if setting == nil { setting = gomail.SetPartEncoding(gomail.Unencoded) } opt.Body = Body{contentType, content, setting} } } func WithAlternativeBody(contentType string, content string, setting gomail.PartSetting) func(*SendOption) { return func(opt *SendOption) { if setting == nil { setting = gomail.SetPartEncoding(gomail.Unencoded) } opt.AlternativeBodies = append(opt.AlternativeBodies, Body{contentType, content, setting}) } } func (m *Mailer) Send(funcs ...SendFunc) error { opt := &SendOption{ Charset: "UTF-8", Body: Body{ Type: "text/plain", Content: "", PartSetting: gomail.SetPartEncoding(gomail.Unencoded), }, AddressHeaders: make([]AddressHeader, 0), Headers: make([]Header, 0), AlternativeBodies: make([]Body, 0), } for _, f := range funcs { f(opt) } conn, err := m.openConnection() if err != nil { return errors.Wrap(err, "could not open connection") } defer conn.Close() message := gomail.NewMessage(gomail.SetCharset(opt.Charset)) for _, h := range opt.AddressHeaders { message.SetAddressHeader(h.Field, h.Address, h.Name) } for _, h := range opt.Headers { message.SetHeader(h.Field, h.Values...) } message.SetBody(opt.Body.Type, opt.Body.Content, opt.Body.PartSetting) for _, b := range opt.AlternativeBodies { message.AddAlternative(b.Type, b.Content, b.PartSetting) } if err := gomail.Send(conn, message); err != nil { return errors.Wrap(err, "could not send message") } return nil } func (m *Mailer) openConnection() (gomail.SendCloser, error) { dialer := gomail.NewDialer( m.opt.Host, m.opt.Port, m.opt.User, m.opt.Password, ) if m.opt.InsecureSkipVerify { dialer.TLSConfig = &tls.Config{ InsecureSkipVerify: true, } } conn, err := dialer.Dial() if err != nil { return nil, errors.Wrap(err, "could not dial smtp server") } return conn, nil }