全部博文(150)
分类: 系统运维
2018-02-07 16:47:13
最近需要使用小米的开源监控系统falcon,开了一个虚拟机进行研究,,发现比较容易上手,并且比较灵活,于是走了一整套的监控流程,设置监控项测试邮件报警等等,其中发现其中发送邮件的模块 mail provider 暂未支持ssl方式发送邮件,鉴于我们目前大部分邮箱系统都已经支持ssl这种更安全的发送方式了,决定修改源码增加ssl的支持。
准备环境
见 falcon server端安装与配置 这里就略过。
克隆代码
git clone
项目结构
[root@falcon mail-provider]# tree . ├── cfg.json ##主配置文件,邮箱登录账号信息 ├── config ##读取主配置文件 │ ├── config.go │ └── const.go ├── control ##编译完成的可执行程序的启动脚本 ├── http ##简单http模块,完成发送邮件功能 │ ├── common.go │ ├── http.go │ └── mail.go ├── main.go ##程序入口 └── README.md 2 directories, 9 files
通过main.go的分析,确定http/mail.go为发邮件文件
mail.go分析
源码如下,第27、28行是调用smtp模块进行发送,修改就从这里入手
1 package http
2
3 import (
4 "net/http"
5 "strings"
6
7 "github.com/open-falcon/mail-provider/config"
8 "github.com/toolkits/smtp"
9 "github.com/toolkits/web/param"
10 )
11
12 func configProcRoutes() {
13
14 http.HandleFunc("/sender/mail", func(w http.ResponseWriter, r *h ttp.Request) {
15 cfg := config.Config()
16 token := param.String(r, "token", "")
17 if cfg.Http.Token != token {
18 http.Error(w, "no privilege", http.StatusForbidd en)
19 return
20 }
21
22 tos := param.MustString(r, "tos")
23 subject := param.MustString(r, "subject")
24 content := param.MustString(r, "content")
25 tos = strings.Replace(tos, ",", ";", -1)
26
27 s := smtp.New(cfg.Smtp.Addr, cfg.Smtp.Username, cfg.Smtp .Password)
28 err := s.SendMail(cfg.Smtp.From, tos, subject, content)
29 if err != nil {
30 http.Error(w, err.Error(), http.StatusInternalSe rverError)
31 } else {
32 http.Error(w, "success", http.StatusOK)
33 }
34 })
35
36 }
修改思路
修改上述的发邮件的函数入口,增加一个SslMail函数,用SslMail替换上述入口
修改后的mail.go
1 package http
2
3 import (
4 "fmt"
5 "net"
6 "net/http"
7 "log"
8 "net/mail"
9 "net/smtp"
10 "crypto/tls"
11 "strings"
12
13
14 "github.com/open-falcon/mail-provider/config"
15 "github.com/toolkits/web/param"
16 )
17
18 func configProcRoutes() {
19
20 http.HandleFunc("/mail", func(w http.ResponseWriter, r *http.Req uest) {
21 cfg := config.Config()
22 token := param.String(r, "token", "")
23 if cfg.Http.Token != token {
24 http.Error(w, "no privilege", http.StatusForbidd en)
25 return
26 }
27
28 tos := param.MustString(r, "tos")
29 //fmt.Println("传入的tos:",tos)
30 subject := param.MustString(r, "subject")
31 content := param.MustString(r, "content")
32 tos = strings.Replace(tos, ",", ";", -1)
33 //fmt.Println("替换后的tos:",tos)
34 err := SslMail(tos, subject, content)
35 if err != nil {
36 http.Error(w, err.Error(), http.StatusInternalSe rverError)
37 } else {
38 http.Error(w, "success", http.StatusOK)
39 }
40 })
41
42 }
43
44 // SSL/TLS Email
45
46 func SslMail(tos string, subject string, content string) error {
47
48
49 cfg := config.Config()
50
51 from := mail.Address{"",cfg.Smtp.From}
52 to := tos
53 toaddr := strings.Split(tos, ";")
54 fmt.Println("toaddr:",toaddr)
55 subj := subject
56 body := content
57
58
59 // Setup headers
60 headers := make(map[string]string)
61 headers["From"] = from.String()
62 // headers["To"] = to.String()
63 headers["To"] = to
64 headers["Subject"] = subj
65
66 // Setup message
67 message := ""
68 for k,v := range headers {
69 message += fmt.Sprintf("%s: %s\r\n", k, v)
70 }
71 message += "\r\n" + body
72
73 // Connect to the SMTP Server
74 servername := cfg.Smtp.Addr
75 host, _, _ := net.SplitHostPort(servername)
76
77 auth := smtp.PlainAuth("",cfg.Smtp.Username, cfg.Smtp.Password, hos t)
78
79 // TLS config
80 tlsconfig := &tls.Config {
81 InsecureSkipVerify: true,
82 ServerName: host,
83 }
84
85 // Here is the key, you need to call tls.Dial instead of smtp.Dial
86 // for smtp servers running on 465 that require an ssl connection
87 // from the very beginning (no starttls)
88 conn, err := tls.Dial("tcp", servername, tlsconfig)
89 if err != nil {
90 log.Panic(err)
91 return err
92 }
93
94 c, err := smtp.NewClient(conn, host)
95 if err != nil {
96 log.Panic(err)
97 return err
98 }
99
100 // Auth
101 if err = c.Auth(auth); err != nil {
102 log.Panic(err)
103 return err
104 }
105
106 // To && From
107 if err = c.Mail(from.Address); err != nil {
108 log.Panic(err)
109 return err
110 }
111
112 for _, addr := range toaddr {
113 if err = c.Rcpt(addr); err != nil {
114 log.Panic(err)
115 return err
116 }
117 }
118
119 // Data
120 w, err := c.Data()
121 if err != nil {
122 log.Panic(err)
123 return err
124 }
125
126 _, err = w.Write([]byte(message))
127 if err != nil {
128 log.Panic(err)
129 return err
130 }
131
132 err = w.Close()
133 if err != nil {
134 log.Panic(err)
135 return err
136 }
137 c.Quit()
138 return nil
139
140 }
运行go build进行编译得到可执行程序
[root@falcon mail-provider]# go build
运行control脚本运行
./control start
查看日志
tail -f var/app.log
目前仅支持ssl发送邮件
后续考虑兼容加密和非加密两种发送方式,通过cfg.json增加“ssl:true",来判断是否启动ssl发送。
后续加入单元测试