mailer.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package mailer
  5. import (
  6. "crypto/tls"
  7. "fmt"
  8. "net"
  9. "net/mail"
  10. "net/smtp"
  11. "os"
  12. "strings"
  13. "github.com/grafana/grafana/pkg/bus"
  14. "github.com/grafana/grafana/pkg/log"
  15. "github.com/grafana/grafana/pkg/notifications"
  16. "github.com/grafana/grafana/pkg/setting"
  17. )
  18. var mailQueue chan *notifications.SendEmailCommand
  19. func Init() {
  20. bus.AddHandler("email", handleEmailCommand)
  21. mailQueue = make(chan *notifications.SendEmailCommand, 10)
  22. setting.Smtp = setting.SmtpSettings{
  23. Host: "smtp.gmail.com:587",
  24. User: "torkel.odegaard@gmail.com",
  25. Password: "peslpwstnnloiksq",
  26. FromAddress: "grafana@grafana.org",
  27. }
  28. go processMailQueue()
  29. }
  30. func processMailQueue() {
  31. for {
  32. select {
  33. case msg := <-mailQueue:
  34. num, err := buildAndSend(msg)
  35. tos := strings.Join(msg.To, "; ")
  36. info := ""
  37. if err != nil {
  38. if len(msg.Info) > 0 {
  39. info = ", info: " + msg.Info
  40. }
  41. log.Error(4, fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err))
  42. } else {
  43. log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info))
  44. }
  45. }
  46. }
  47. }
  48. func encodeRFC2047(text string) string {
  49. // use mail's rfc2047 to encode any string
  50. addr := mail.Address{Address: text}
  51. return strings.Trim(addr.String(), " <>")
  52. }
  53. func handleEmailCommand(cmd *notifications.SendEmailCommand) error {
  54. log.Info("Sending on queue")
  55. mailQueue <- cmd
  56. return nil
  57. }
  58. func sendToSmtpServer(recipients []string, msgContent []byte) error {
  59. host, port, err := net.SplitHostPort(setting.Smtp.Host)
  60. if err != nil {
  61. return err
  62. }
  63. tlsconfig := &tls.Config{
  64. InsecureSkipVerify: setting.Smtp.SkipVerify,
  65. ServerName: host,
  66. }
  67. if setting.Smtp.CertFile != "" {
  68. cert, err := tls.LoadX509KeyPair(setting.Smtp.CertFile, setting.Smtp.KeyFile)
  69. if err != nil {
  70. return err
  71. }
  72. tlsconfig.Certificates = []tls.Certificate{cert}
  73. }
  74. conn, err := net.Dial("tcp", net.JoinHostPort(host, port))
  75. if err != nil {
  76. return err
  77. }
  78. defer conn.Close()
  79. isSecureConn := false
  80. // Start TLS directly if the port ends with 465 (SMTPS protocol)
  81. if strings.HasSuffix(port, "465") {
  82. conn = tls.Client(conn, tlsconfig)
  83. isSecureConn = true
  84. }
  85. client, err := smtp.NewClient(conn, host)
  86. if err != nil {
  87. return err
  88. }
  89. hostname, err := os.Hostname()
  90. if err != nil {
  91. return err
  92. }
  93. if err = client.Hello(hostname); err != nil {
  94. return err
  95. }
  96. // If not using SMTPS, alway use STARTTLS if available
  97. hasStartTLS, _ := client.Extension("STARTTLS")
  98. if !isSecureConn && hasStartTLS {
  99. if err = client.StartTLS(tlsconfig); err != nil {
  100. return err
  101. }
  102. }
  103. canAuth, options := client.Extension("AUTH")
  104. if canAuth && len(setting.Smtp.User) > 0 {
  105. var auth smtp.Auth
  106. if strings.Contains(options, "CRAM-MD5") {
  107. auth = smtp.CRAMMD5Auth(setting.Smtp.User, setting.Smtp.Password)
  108. } else if strings.Contains(options, "PLAIN") {
  109. auth = smtp.PlainAuth("", setting.Smtp.User, setting.Smtp.Password, host)
  110. }
  111. if auth != nil {
  112. if err = client.Auth(auth); err != nil {
  113. return err
  114. }
  115. }
  116. }
  117. if fromAddress, err := mail.ParseAddress(setting.Smtp.FromAddress); err != nil {
  118. return err
  119. } else {
  120. if err = client.Mail(fromAddress.Address); err != nil {
  121. return err
  122. }
  123. }
  124. for _, rec := range recipients {
  125. if err = client.Rcpt(rec); err != nil {
  126. return err
  127. }
  128. }
  129. w, err := client.Data()
  130. if err != nil {
  131. return err
  132. }
  133. if _, err = w.Write([]byte(msgContent)); err != nil {
  134. return err
  135. }
  136. if err = w.Close(); err != nil {
  137. return err
  138. }
  139. return client.Quit()
  140. // smtpServer := "smtp.gmail.com"
  141. // auth := smtp.PlainAuth(
  142. // "",
  143. // "torkel.odegaard@gmail.com",
  144. // "peslpwstnnloiksq",
  145. // smtpServer,
  146. // )
  147. //
  148. // from := mail.Address{Name: "test", Address: "torkel@test.com"}
  149. // to := mail.Address{Name: "Torkel Ödegaard", Address: "torkel@raintank.io"}
  150. // title := "Message from Grafana"
  151. //
  152. // body := "Testing email sending"
  153. //
  154. // header := make(map[string]string)
  155. // header["From"] = from.String()
  156. // header["To"] = to.String()
  157. // header["Subject"] = encodeRFC2047(title)
  158. // header["MIME-Version"] = "1.0"
  159. // header["Content-Type"] = "text/plain; charset=\"utf-8\""
  160. // header["Content-Transfer-Encoding"] = "base64"
  161. //
  162. // message := ""
  163. // for k, v := range header {
  164. // message += fmt.Sprintf("%s: %s\r\n", k, v)
  165. // }
  166. // message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
  167. //
  168. // // Connect to the server, authenticate, set the sender and recipient,
  169. // // and send the email all in one step.
  170. // err := smtp.SendMail(
  171. // smtpServer+":587",
  172. // auth,
  173. // from.Address,
  174. // []string{to.Address},
  175. // []byte(message),
  176. // )
  177. // if err != nil {
  178. // log.Info("Failed to send email: %v", err)
  179. // }
  180. // kkkk
  181. }
  182. func buildAndSend(msg *m.SendEmailCommand) (int, error) {
  183. log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
  184. // get message body
  185. content := msg.Content()
  186. if len(msg.To) == 0 {
  187. return 0, fmt.Errorf("empty receive emails")
  188. } else if len(msg.Body) == 0 {
  189. return 0, fmt.Errorf("empty email body")
  190. }
  191. if msg.Massive {
  192. // send mail to multiple emails one by one
  193. num := 0
  194. for _, to := range msg.To {
  195. body := []byte("To: " + to + "\r\n" + content)
  196. err := sendToSmtpServer([]string{to}, body)
  197. if err != nil {
  198. return num, err
  199. }
  200. num++
  201. }
  202. return num, nil
  203. } else {
  204. body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
  205. // send to multiple emails in one message
  206. err := sendToSmtpServer(msg.To, body)
  207. if err != nil {
  208. return 0, err
  209. } else {
  210. return 1, nil
  211. }
  212. }
  213. }