hydra-passwordless/internal/mail/send.go

161 lines
3.5 KiB
Go

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
}