diff --git a/go.mod b/go.mod index 44e510e..c867eb1 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/BurntSushi/toml v1.4.0 github.com/KimMachineGun/automemlimit v0.7.0 github.com/PuerkitoBio/goquery v1.10.1 - github.com/Shopify/gomail v0.0.0-20220729171026-0784ece65e69 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/avast/retry-go/v4 v4.6.0 github.com/blang/semver/v4 v4.0.0 @@ -33,6 +32,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 github.com/tj/go-spin v1.1.0 + github.com/wneessen/go-mail v0.6.0 go.uber.org/automaxprocs v1.6.0 go.uber.org/goleak v1.3.0 go.uber.org/ratelimit v0.3.1 @@ -94,6 +94,5 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.2 // indirect - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 18e8719..98811f0 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,6 @@ github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlD github.com/KimMachineGun/automemlimit v0.7.0/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU= github.com/PuerkitoBio/goquery v1.10.1/go.mod h1:IYiHrOMps66ag56LEH7QYDDupKXyo5A8qrjIx3ZtujY= -github.com/Shopify/gomail v0.0.0-20220729171026-0784ece65e69 h1:gPoXdwo3sKq8qcfMu/Nc/wkJMLKwe7kaG9Uo8tOj3cU= -github.com/Shopify/gomail v0.0.0-20220729171026-0784ece65e69/go.mod h1:RS+Gaowa0M+gCuiFAiRMGBCMqxLrNA7TESTU/Wbblm8= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= @@ -218,6 +216,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/wneessen/go-mail v0.6.0 h1:wO7EeJ8RL6DD+aycFGntil6b11g3FNQpQQQC1gkm97Y= +github.com/wneessen/go-mail v0.6.0/go.mod h1:G702XlFhzHV0Z4w9j2VsH5K9dJDvj0hx+yOOp1oX9vc= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -322,6 +322,7 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -373,13 +374,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= -gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/messenger/mail.go b/messenger/mail.go index 2b6605c..985207e 100644 --- a/messenger/mail.go +++ b/messenger/mail.go @@ -27,11 +27,11 @@ import ( "strconv" "time" - mail "github.com/Shopify/gomail" "github.com/avast/retry-go/v4" "github.com/dkorunic/e-dnevnik-bot/format" "github.com/dkorunic/e-dnevnik-bot/logger" "github.com/dkorunic/e-dnevnik-bot/msgtypes" + mail "github.com/wneessen/go-mail" "go.uber.org/ratelimit" ) @@ -43,8 +43,9 @@ const ( ) var ( - ErrMailSendingMessage = errors.New("error sending mail message") - ErrMailInvalidPort = errors.New("invalid or missing SMTP port, will try with default 587/tcp") + ErrMailInvalidPort = errors.New("invalid or missing SMTP port, will try with default 587/tcp") + ErrMailDialer = errors.New("failed to create mail delivery client") + ErrMailSendingMessages = errors.New("error sending mail messages") ) // Mail sends a message through the mail service. @@ -92,40 +93,58 @@ func Mail(ctx context.Context, ch <-chan interface{}, server, port, username, pa htmlContent := format.HTMLMsg(g.Username, g.Subject, g.IsExam, g.Descriptions, g.Fields) // establish dialer - d := mail.NewDialer(server, portInt, username, password) - d.StartTLSPolicy = mail.OpportunisticStartTLS + d, err := mail.NewClient(server, + mail.WithPort(portInt), + mail.WithSMTPAuth(mail.SMTPAuthPlain), + mail.WithTLSPolicy(mail.TLSOpportunistic), + mail.WithUsername(username), + mail.WithPassword(password), + ) + if err != nil { + logger.Error().Msgf("%v: %v", ErrMailDialer, err) + + break + } + + var messages []*mail.Msg - // send to all recipients + // bulk send to all recipients for _, u := range to { - m := mail.NewMessage() - m.SetHeader("From", from) - m.SetHeader("To", u) + m := mail.NewMsg() + _ = m.From(from) + _ = m.To(u) + + m.SetMessageID() + m.SetDate() + m.SetBulk() if subject != "" { - m.SetHeader("Subject", subject) + m.Subject(subject) } else { - m.SetHeader("Subject", MailSubject) + m.Subject(MailSubject) } - m.SetBody("text/plain", plainContent) - m.AddAlternative("text/html", htmlContent) + m.SetBodyString(mail.TypeTextPlain, plainContent) + m.SetBodyString(mail.TypeTextHTML, htmlContent) - rl.Take() - - // retryable and cancellable attempt to send a message - err = retry.Do( - func() error { - return d.DialAndSend(m) - }, - retry.Attempts(retries), - retry.Context(ctx), - retry.Delay(MailMinDelay), - ) - if err != nil { - logger.Error().Msgf("%v: %v", ErrMailSendingMessage, err) + messages = append(messages, m) + } - break - } + rl.Take() + + // retryable and cancellable attempt to send a message + err = retry.Do( + func() error { + return d.DialAndSend(messages...) + }, + retry.Attempts(retries), + retry.Context(ctx), + retry.Delay(MailMinDelay), + ) + if err != nil { + logger.Error().Msgf("%v: %v", ErrMailSendingMessages, err) + + break } } }