| 
									
										
										
										
											2015-06-04 23:23:46 +08:00
										 |  |  | // Copyright 2014 The Gogs Authors. All rights reserved.
 | 
					
						
							|  |  |  | // Use of this source code is governed by a MIT-style
 | 
					
						
							|  |  |  | // license that can be found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-08 22:51:25 +08:00
										 |  |  | package notifications | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	"crypto/tls" | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 	"html/template" | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/log" | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 	m "github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	"gopkg.in/gomail.v2" | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-08 22:51:25 +08:00
										 |  |  | var mailQueue chan *Message | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-08 22:51:25 +08:00
										 |  |  | func initMailQueue() { | 
					
						
							|  |  |  | 	mailQueue = make(chan *Message, 10) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	go processMailQueue() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func processMailQueue() { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case msg := <-mailQueue: | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 			num, err := send(msg) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 			tos := strings.Join(msg.To, "; ") | 
					
						
							|  |  |  | 			info := "" | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				if len(msg.Info) > 0 { | 
					
						
							|  |  |  | 					info = ", info: " + msg.Info | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				log.Error(4, fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err)) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-08 22:51:25 +08:00
										 |  |  | var addToMailQueue = func(msg *Message) { | 
					
						
							|  |  |  | 	mailQueue <- msg | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | func send(msg *Message) (int, error) { | 
					
						
							|  |  |  | 	dialer, err := createDialer() | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 		return 0, err | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 	for _, address := range msg.To { | 
					
						
							|  |  |  | 		m := gomail.NewMessage() | 
					
						
							|  |  |  | 		m.SetHeader("From", msg.From) | 
					
						
							|  |  |  | 		m.SetHeader("To", address) | 
					
						
							|  |  |  | 		m.SetHeader("Subject", msg.Subject) | 
					
						
							|  |  |  | 		for _, file := range msg.EmbededFiles { | 
					
						
							|  |  |  | 			m.Embed(file) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 		m.SetBody("text/html", msg.Body) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 		if err := dialer.DialAndSend(m); err != nil { | 
					
						
							|  |  |  | 			return 0, err | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 	return len(msg.To), nil | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | func createDialer() (*gomail.Dialer, error) { | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	host, port, err := net.SplitHostPort(setting.Smtp.Host) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	iPort, err := strconv.Atoi(port) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	tlsconfig := &tls.Config{ | 
					
						
							|  |  |  | 		InsecureSkipVerify: setting.Smtp.SkipVerify, | 
					
						
							|  |  |  | 		ServerName:         host, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if setting.Smtp.CertFile != "" { | 
					
						
							|  |  |  | 		cert, err := tls.LoadX509KeyPair(setting.Smtp.CertFile, setting.Smtp.KeyFile) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-15 15:27:21 +08:00
										 |  |  | 			return nil, fmt.Errorf("Could not load cert or key file. error: %v", err) | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 		tlsconfig.Certificates = []tls.Certificate{cert} | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 05:11:59 +08:00
										 |  |  | 	d := gomail.NewDialer(host, iPort, setting.Smtp.User, setting.Smtp.Password) | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 	d.TLSConfig = tlsconfig | 
					
						
							| 
									
										
										
										
											2017-01-17 17:36:04 +08:00
										 |  |  | 	d.LocalName = setting.InstanceName | 
					
						
							| 
									
										
										
										
											2016-10-20 21:18:12 +08:00
										 |  |  | 	return d, nil | 
					
						
							| 
									
										
										
										
											2015-06-04 20:29:39 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func buildEmailMessage(cmd *m.SendEmailCommand) (*Message, error) { | 
					
						
							|  |  |  | 	if !setting.Smtp.Enabled { | 
					
						
							|  |  |  | 		return nil, errors.New("Grafana mailing/smtp options not configured, contact your Grafana admin") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var buffer bytes.Buffer | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data := cmd.Data | 
					
						
							|  |  |  | 	if data == nil { | 
					
						
							|  |  |  | 		data = make(map[string]interface{}, 10) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setDefaultTemplateData(data, nil) | 
					
						
							|  |  |  | 	err = mailTemplates.ExecuteTemplate(&buffer, cmd.Template, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 21:26:35 +08:00
										 |  |  | 	subject := cmd.Subject | 
					
						
							|  |  |  | 	if cmd.Subject == "" { | 
					
						
							|  |  |  | 		var subjectText interface{} | 
					
						
							|  |  |  | 		subjectData := data["Subject"].(map[string]interface{}) | 
					
						
							|  |  |  | 		subjectText, hasSubject := subjectData["value"] | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 21:26:35 +08:00
										 |  |  | 		if !hasSubject { | 
					
						
							|  |  |  | 			return nil, errors.New(fmt.Sprintf("Missing subject in Template %s", cmd.Template)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 21:26:35 +08:00
										 |  |  | 		subjectTmpl, err := template.New("subject").Parse(subjectText.(string)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 21:26:35 +08:00
										 |  |  | 		var subjectBuffer bytes.Buffer | 
					
						
							|  |  |  | 		err = subjectTmpl.ExecuteTemplate(&subjectBuffer, "subject", data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		subject = subjectBuffer.String() | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &Message{ | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 		To:           cmd.To, | 
					
						
							| 
									
										
										
										
											2017-02-15 04:51:41 +08:00
										 |  |  | 		From:         fmt.Sprintf("%s <%s>", setting.Smtp.FromName, setting.Smtp.FromAddress), | 
					
						
							| 
									
										
										
										
											2016-12-15 21:26:35 +08:00
										 |  |  | 		Subject:      subject, | 
					
						
							| 
									
										
										
										
											2016-10-20 21:06:59 +08:00
										 |  |  | 		Body:         buffer.String(), | 
					
						
							|  |  |  | 		EmbededFiles: cmd.EmbededFiles, | 
					
						
							| 
									
										
										
										
											2016-10-03 15:38:03 +08:00
										 |  |  | 	}, nil | 
					
						
							|  |  |  | } |