Chinaunix首页 | 论坛 | 博客
  • 博客访问: 671924
  • 博文数量: 138
  • 博客积分: 660
  • 博客等级: 上士
  • 技术积分: 2252
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-08 11:39
文章分类

全部博文(138)

文章存档

2018年(28)

2017年(53)

2016年(7)

2015年(3)

2014年(3)

2013年(27)

2012年(2)

2011年(1)

2006年(1)

2005年(13)

分类: 系统运维

2018-02-07 16:47:13

falcon mail provider模块的源码修改--增加ssl方式发送邮件

原因

最近需要使用小米的开源监控系统falcon,开了一个虚拟机进行研究,,发现比较容易上手,并且比较灵活,于是走了一整套的监控流程,设置监控项测试邮件报警等等,其中发现其中发送邮件的模块 mail provider 暂未支持ssl方式发送邮件,鉴于我们目前大部分邮箱系统都已经支持ssl这种更安全的发送方式了,决定修改源码增加ssl的支持。

源码分析与修改

  • 准备环境

      falcon server端安装与配置 这里就略过。

  • 克隆代码

    git clone https://github.com/open-falcon/mail-provider.git

  • 项目结构

[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发送。

  • 后续加入单元测试

致谢与参考

Golang SSL SMTP Example · GitHub

zzlyzq fork后修改

使用ssl连接发送邮件

阅读(1899) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册