From 12a9180807f6e1e53023de001eb7f1e611026a91 Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Mon, 21 Aug 2017 15:31:13 -0300 Subject: [PATCH] [PLT-1015] Make all Mattermost system emails Multi-Part, with both a HTML and Plain Text version. (#5698) * Implementation to Make all Mattermost system emails Multi-Part, with both a HTML and Plain Text version * update lib * update code per review * update to use the mattermost repo --- NOTICE.txt | 2 +- app/admin.go | 1 - app/email_batching.go | 2 +- app/email_test.go | 4 ++-- utils/mail.go | 47 ++++++++++++++++++++++++------------------- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index b4eacb90dda..2e694684c11 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -4655,7 +4655,7 @@ MIT license This product contains a modified portion of 'html2text', an HTML to raw text converter by Carlos Tadeu Panato Junior, based on `html2text` by Jay Taylor. * HOMEPAGE - * https://github.com/cpanato/html2text + * https://github.com/mattermost/html2text * LICENSE diff --git a/app/admin.go b/app/admin.go index 50ed769b60b..b9e22a87f50 100644 --- a/app/admin.go +++ b/app/admin.go @@ -212,7 +212,6 @@ func TestEmail(userId string, cfg *model.Config) *model.AppError { return model.NewLocAppError("testEmail", "api.admin.test_email.reenter_password", nil, "") } } - if user, err := GetUser(userId); err != nil { return err } else { diff --git a/app/email_batching.go b/app/email_batching.go index b37963a9417..e2a2286ce4f 100644 --- a/app/email_batching.go +++ b/app/email_batching.go @@ -218,7 +218,7 @@ func sendBatchedEmailNotification(userId string, notifications []*batchedNotific body.Props["BodyText"] = translateFunc("api.email_batching.send_batched_email_notification.body_text", len(notifications)) if err := utils.SendMail(user.Email, subject, body.Render()); err != nil { - l4g.Warn(utils.T("api.email_batching.send_batched_email_notification.send.app_error"), user.Email, err) + l4g.Warn(utils.T("api.email_batchings.send_batched_email_notification.send.app_error"), user.Email, err) } } diff --git a/app/email_test.go b/app/email_test.go index 67457c70264..449e81b75fb 100644 --- a/app/email_test.go +++ b/app/email_test.go @@ -70,7 +70,7 @@ func TestSendEmailChangeVerifyEmail(t *testing.T) { var newUserEmail string = "newtest@example.com" var locale string = "en" - var siteURL string = "" + var siteURL string = "http://localhost:8065" var expectedPartialMessage string = "You updated your email" var expectedSubject string = "[" + utils.Cfg.TeamSettings.SiteName + "] Verify new email address" var token string = "TEST_TOKEN" @@ -174,7 +174,7 @@ func TestSendVerifyEmail(t *testing.T) { var userEmail string = "test@example.com" var locale string = "en" - var siteURL string = "" + var siteURL string = "http://localhost:8605" var expectedPartialMessage string = "Please verify your email address by clicking below" var expectedSubject string = "[" + utils.Cfg.TeamSettings.SiteName + "] Email Verification" var token string = "TEST_TOKEN" diff --git a/utils/mail.go b/utils/mail.go index 41011d67e9a..6e87e5731d5 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -5,14 +5,16 @@ package utils import ( "crypto/tls" - "fmt" "mime" "net" "net/mail" "net/smtp" "time" + "gopkg.in/gomail.v2" + l4g "github.com/alecthomas/log4go" + "github.com/mattermost/html2text" "github.com/mattermost/platform/model" ) @@ -99,34 +101,38 @@ func TestConnection(config *model.Config) { defer c.Close() } -func SendMail(to, subject, body string) *model.AppError { - return SendMailUsingConfig(to, subject, body, Cfg) +func SendMail(to, subject, htmlBody string) *model.AppError { + return SendMailUsingConfig(to, subject, htmlBody, Cfg) } -func SendMailUsingConfig(to, subject, body string, config *model.Config) *model.AppError { +func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config) *model.AppError { if !config.EmailSettings.SendEmailNotifications || len(config.EmailSettings.SMTPServer) == 0 { return nil } l4g.Debug(T("utils.mail.send_mail.sending.debug"), to, subject) - fromMail := mail.Address{Name: config.EmailSettings.FeedbackName, Address: config.EmailSettings.FeedbackEmail} - toMail := mail.Address{Name: "", Address: to} + htmlMessage := "\r\n" + htmlBody + "" - headers := make(map[string]string) - headers["From"] = fromMail.String() - headers["To"] = toMail.String() - headers["Subject"] = encodeRFC2047Word(subject) - headers["MIME-version"] = "1.0" - headers["Content-Type"] = "text/html; charset=\"utf-8\"" - headers["Content-Transfer-Encoding"] = "8bit" - headers["Date"] = time.Now().Format(time.RFC1123Z) + fromMail := mail.Address{Name: config.EmailSettings.FeedbackName, Address: config.EmailSettings.FeedbackEmail} - message := "" - for k, v := range headers { - message += fmt.Sprintf("%s: %s\r\n", k, v) + txtBody, err := html2text.FromString(htmlBody) + if err != nil { + l4g.Warn(err) + txtBody = "" } - message += "\r\n" + body + "" + + m := gomail.NewMessage(gomail.SetCharset("UTF-8")) + m.SetHeaders(map[string][]string{ + "From": {fromMail.String()}, + "To": {to}, + "Subject": {encodeRFC2047Word(subject)}, + "Content-Transfer-Encoding": {"8bit"}, + }) + m.SetDateHeader("Date", time.Now()) + + m.SetBody("text/plain", txtBody) + m.AddAlternative("text/html", htmlMessage) conn, err1 := connectToSMTPServer(config) if err1 != nil { @@ -145,7 +151,7 @@ func SendMailUsingConfig(to, subject, body string, config *model.Config) *model. return model.NewLocAppError("SendMail", "utils.mail.send_mail.from_address.app_error", nil, err.Error()) } - if err := c.Rcpt(toMail.Address); err != nil { + if err := c.Rcpt(to); err != nil { return model.NewLocAppError("SendMail", "utils.mail.send_mail.to_address.app_error", nil, err.Error()) } @@ -154,11 +160,10 @@ func SendMailUsingConfig(to, subject, body string, config *model.Config) *model. return model.NewLocAppError("SendMail", "utils.mail.send_mail.msg_data.app_error", nil, err.Error()) } - _, err = w.Write([]byte(message)) + _, err = m.WriteTo(w) if err != nil { return model.NewLocAppError("SendMail", "utils.mail.send_mail.msg.app_error", nil, err.Error()) } - err = w.Close() if err != nil { return model.NewLocAppError("SendMail", "utils.mail.send_mail.close.app_error", nil, err.Error())