全部博文(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发送。
后续加入单元测试