github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/utils/mail.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package utils 5 6 import ( 7 "crypto/tls" 8 "mime" 9 "net" 10 "net/mail" 11 "net/smtp" 12 "time" 13 14 "gopkg.in/gomail.v2" 15 16 "net/http" 17 18 l4g "github.com/alecthomas/log4go" 19 "github.com/mattermost/html2text" 20 "github.com/mattermost/mattermost-server/model" 21 ) 22 23 func encodeRFC2047Word(s string) string { 24 return mime.BEncoding.Encode("utf-8", s) 25 } 26 27 func connectToSMTPServer(config *model.Config) (net.Conn, *model.AppError) { 28 var conn net.Conn 29 var err error 30 31 if config.EmailSettings.ConnectionSecurity == model.CONN_SECURITY_TLS { 32 tlsconfig := &tls.Config{ 33 InsecureSkipVerify: *config.EmailSettings.SkipServerCertificateVerification, 34 ServerName: config.EmailSettings.SMTPServer, 35 } 36 37 conn, err = tls.Dial("tcp", config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort, tlsconfig) 38 if err != nil { 39 return nil, model.NewAppError("SendMail", "utils.mail.connect_smtp.open_tls.app_error", nil, err.Error(), http.StatusInternalServerError) 40 } 41 } else { 42 conn, err = net.Dial("tcp", config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) 43 if err != nil { 44 return nil, model.NewAppError("SendMail", "utils.mail.connect_smtp.open.app_error", nil, err.Error(), http.StatusInternalServerError) 45 } 46 } 47 48 return conn, nil 49 } 50 51 func newSMTPClient(conn net.Conn, config *model.Config) (*smtp.Client, *model.AppError) { 52 c, err := smtp.NewClient(conn, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) 53 if err != nil { 54 l4g.Error(T("utils.mail.new_client.open.error"), err) 55 return nil, model.NewAppError("SendMail", "utils.mail.connect_smtp.open_tls.app_error", nil, err.Error(), http.StatusInternalServerError) 56 } 57 58 hostname := GetHostnameFromSiteURL(*config.ServiceSettings.SiteURL) 59 if hostname != "" { 60 err := c.Hello(hostname) 61 if err != nil { 62 l4g.Error(T("utils.mail.new_client.helo.error"), err) 63 return nil, model.NewAppError("SendMail", "utils.mail.connect_smtp.helo.app_error", nil, err.Error(), http.StatusInternalServerError) 64 } 65 } 66 67 if config.EmailSettings.ConnectionSecurity == model.CONN_SECURITY_STARTTLS { 68 tlsconfig := &tls.Config{ 69 InsecureSkipVerify: *config.EmailSettings.SkipServerCertificateVerification, 70 ServerName: config.EmailSettings.SMTPServer, 71 } 72 c.StartTLS(tlsconfig) 73 } 74 75 if *config.EmailSettings.EnableSMTPAuth { 76 auth := smtp.PlainAuth("", config.EmailSettings.SMTPUsername, config.EmailSettings.SMTPPassword, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) 77 78 if err = c.Auth(auth); err != nil { 79 return nil, model.NewAppError("SendMail", "utils.mail.new_client.auth.app_error", nil, err.Error(), http.StatusInternalServerError) 80 } 81 } 82 return c, nil 83 } 84 85 func TestConnection(config *model.Config) { 86 if !config.EmailSettings.SendEmailNotifications { 87 return 88 } 89 90 conn, err1 := connectToSMTPServer(config) 91 if err1 != nil { 92 l4g.Error(T("utils.mail.test.configured.error"), T(err1.Message), err1.DetailedError) 93 return 94 } 95 defer conn.Close() 96 97 c, err2 := newSMTPClient(conn, config) 98 if err2 != nil { 99 l4g.Error(T("utils.mail.test.configured.error"), T(err2.Message), err2.DetailedError) 100 return 101 } 102 defer c.Quit() 103 defer c.Close() 104 } 105 106 func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config) *model.AppError { 107 if !config.EmailSettings.SendEmailNotifications || len(config.EmailSettings.SMTPServer) == 0 { 108 return nil 109 } 110 111 l4g.Debug(T("utils.mail.send_mail.sending.debug"), to, subject) 112 113 htmlMessage := "\r\n<html><body>" + htmlBody + "</body></html>" 114 115 fromMail := mail.Address{Name: config.EmailSettings.FeedbackName, Address: config.EmailSettings.FeedbackEmail} 116 117 txtBody, err := html2text.FromString(htmlBody) 118 if err != nil { 119 l4g.Warn(err) 120 txtBody = "" 121 } 122 123 m := gomail.NewMessage(gomail.SetCharset("UTF-8")) 124 m.SetHeaders(map[string][]string{ 125 "From": {fromMail.String()}, 126 "To": {to}, 127 "Subject": {encodeRFC2047Word(subject)}, 128 "Content-Transfer-Encoding": {"8bit"}, 129 "Auto-Submitted": {"auto-generated"}, 130 "Precedence": {"bulk"}, 131 }) 132 m.SetDateHeader("Date", time.Now()) 133 134 m.SetBody("text/plain", txtBody) 135 m.AddAlternative("text/html", htmlMessage) 136 137 conn, err1 := connectToSMTPServer(config) 138 if err1 != nil { 139 return err1 140 } 141 defer conn.Close() 142 143 c, err2 := newSMTPClient(conn, config) 144 if err2 != nil { 145 return err2 146 } 147 defer c.Quit() 148 defer c.Close() 149 150 if err := c.Mail(fromMail.Address); err != nil { 151 return model.NewAppError("SendMail", "utils.mail.send_mail.from_address.app_error", nil, err.Error(), http.StatusInternalServerError) 152 } 153 154 if err := c.Rcpt(to); err != nil { 155 return model.NewAppError("SendMail", "utils.mail.send_mail.to_address.app_error", nil, err.Error(), http.StatusInternalServerError) 156 } 157 158 w, err := c.Data() 159 if err != nil { 160 return model.NewAppError("SendMail", "utils.mail.send_mail.msg_data.app_error", nil, err.Error(), http.StatusInternalServerError) 161 } 162 163 _, err = m.WriteTo(w) 164 if err != nil { 165 return model.NewAppError("SendMail", "utils.mail.send_mail.msg.app_error", nil, err.Error(), http.StatusInternalServerError) 166 } 167 err = w.Close() 168 if err != nil { 169 return model.NewAppError("SendMail", "utils.mail.send_mail.close.app_error", nil, err.Error(), http.StatusInternalServerError) 170 } 171 172 return nil 173 }