]> source.dussan.org Git - gitea.git/commitdiff
Rewrite of SendMail function
authorPeter <peter@smitmail.eu>
Thu, 18 Dec 2014 11:34:30 +0000 (13:34 +0200)
committerPeter <peter@smitmail.eu>
Thu, 18 Dec 2014 11:34:30 +0000 (13:34 +0200)
The SendMail function is rewritten and has the following new functionality:
 - It is optional to skip verification of keys. The config option SKIP_VERIFY is added
 - If the port is 465, or ending on 465, the TLS(/SSL) connection is started first.

conf/app.ini
modules/mailer/mailer.go
modules/setting/setting.go

index 1c7c70befacc61a7163568992d0903bf868abc49..d6ee6ae4d434e4d94b8ae3048a34dfdfcacba72e 100644 (file)
@@ -94,7 +94,10 @@ SUBJECT = %(APP_NAME)s
 ; Mail server
 ; Gmail: smtp.gmail.com:587
 ; QQ: smtp.qq.com:25
+; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used.
 HOST =
+; Do not verify the certificate of the server. Only use this for self-signed certificates
+SKIP_VERIFY = 
 ; Mail from address
 FROM =
 ; Mailer user name and password
index 474e1481cd54b8fc1138a6318cf9e28bc6754419..6d75fa3f2c8085ac537ffe0ed3e805f6252454c2 100644 (file)
@@ -67,22 +67,53 @@ func processMailQueue() {
 }
 
 // sendMail allows mail with self-signed certificates.
-func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error {
-       client, err := smtp.Dial(hostAddressWithPort)
+func sendMail(settings *setting.Mailer, from string, recipients []string, msgContent []byte) error {
+       host, port, err := net.SplitHostPort(settings.Host)
        if err != nil {
                return err
        }
 
-       host, _, _ := net.SplitHostPort(hostAddressWithPort)
-       tlsConn := &tls.Config{
-               InsecureSkipVerify: true,
+       if len(port) == 0 {
+               port = "587"
+       }
+
+       tlsconfig := &tls.Config{
+               InsecureSkipVerify: settings.SkipVerify,
                ServerName:         host,
        }
-       if err = client.StartTLS(tlsConn); err != nil {
+
+       var conn net.Conn
+       if conn, err = net.Dial("tcp", net.JoinHostPort(host, port)); err != nil {
+               return err
+       }
+       defer conn.Close()
+
+       connection_secure := false
+       // Start TLS directly if the port ends with 465 (SMTPS protocol)
+       if strings.HasSuffix(port, "465") {
+               conn = tls.Client(conn, tlsconfig)
+               connection_secure = true
+       }
+
+       var client *smtp.Client
+       if client, err = smtp.NewClient(conn, host); err != nil {
                return err
        }
 
-       if ok, _ := client.Extension("AUTH"); ok && auth != nil {
+       // If not using SMTPS, alway use STARTTLS if available
+       has_starttls, _ := client.Extension("STARTTLS")
+       if !connection_secure && has_starttls {
+               if err = client.StartTLS(tlsconfig); err != nil {
+                       return err
+               }
+       }
+
+       auth_available, _ := client.Extension("AUTH")
+
+       // Possible improvement: only plain authentication is now available.
+       // Maybe in future CRAM MD5 as well?
+       if auth_available && len(settings.User) > 0 {
+               auth := smtp.PlainAuth("", settings.User, settings.Passwd, host)
                if err = client.Auth(auth); err != nil {
                        return err
                }
@@ -116,7 +147,6 @@ func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipient
 // Direct Send mail message
 func Send(msg *Message) (int, error) {
        log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
-       host := strings.Split(setting.MailService.Host, ":")
 
        // get message body
        content := msg.Content()
@@ -127,17 +157,12 @@ func Send(msg *Message) (int, error) {
                return 0, fmt.Errorf("empty email body")
        }
 
-       var auth smtp.Auth
-       if len(setting.MailService.Passwd) > 0 {
-               auth = smtp.PlainAuth("", setting.MailService.User, setting.MailService.Passwd, host[0])
-       }
-
        if msg.Massive {
                // send mail to multiple emails one by one
                num := 0
                for _, to := range msg.To {
                        body := []byte("To: " + to + "\r\n" + content)
-                       err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body)
+                       err := sendMail(setting.MailService, msg.From, []string{to}, body)
                        if err != nil {
                                return num, err
                        }
@@ -148,7 +173,7 @@ func Send(msg *Message) (int, error) {
                body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
 
                // send to multiple emails in one message
-               err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body)
+               err := sendMail(setting.MailService, msg.From, msg.To, body)
                if err != nil {
                        return 0, err
                } else {
index 7765a859ab87a3c7fc39d2ce595cee4e1315c31e..76e1ab76965e385957f0b77fcacc30947a3200fa 100644 (file)
@@ -437,6 +437,7 @@ type Mailer struct {
        Host         string
        From         string
        User, Passwd string
+       SkipVerify   bool
 }
 
 type OauthInfo struct {
@@ -463,10 +464,11 @@ func newMailService() {
        }
 
        MailService = &Mailer{
-               Name:   Cfg.MustValue("mailer", "NAME", AppName),
-               Host:   Cfg.MustValue("mailer", "HOST"),
-               User:   Cfg.MustValue("mailer", "USER"),
-               Passwd: Cfg.MustValue("mailer", "PASSWD"),
+               Name:       Cfg.MustValue("mailer", "NAME", AppName),
+               Host:       Cfg.MustValue("mailer", "HOST"),
+               User:       Cfg.MustValue("mailer", "USER"),
+               Passwd:     Cfg.MustValue("mailer", "PASSWD"),
+               SkipVerify: Cfg.MustBool("mailer", "SKIP_VERIFY", false),
        }
        MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User)
        log.Info("Mail Service Enabled")