golang实现ssl安全邮件发送
一、普通邮件的发送
在golang.org官方页面上,net/smtp模块给出了我们如何直接进行邮件发送和简单的带密码验证的邮件的发送。不过由于不进行tls ssl 安全认证的smtp协议,很容易在网络传输中被抓包获取用户名密码,所以目前各大主流邮箱(QQ、163、gmail)等都不再做为主流(163还在支持),在开始tls加密邮件传输之前,先看下官网的示例(这里用的github上golang项目页的地址):
1package main
2import (
3 "log"
4 "net/smtp"
5)
6func main() {
7 // Set up authentication information.
8 auth := smtp.PlainAuth("", "[email protected]", "password", "mail.example.com")
9 // Connect to the server, authenticate, set the sender and recipient,
10 // and send the email all in one step.
11 to := []string{"[email protected]"}
12 msg := []byte("To: [email protected]\r\n" +
13 "Subject: discount Gophers!\r\n" +
14 "\r\n" +
15 "This is the email body.\r\n")
16 err := smtp.SendMail("mail.example.com:25", auth, "[email protected]", to, msg)
17 if err != nil {
18 log.Fatal(err)
19 }
20}
二、使用tls加密传输的
使用tls传输的,使用的端口是465,不再是默认的25,其需要使用到crypto/tls模块,具体代码如下:
1package main
2import (
3 "crypto/tls"
4 "fmt"
5 "log"
6 "net"
7 "net/smtp"
8)
9func main() {
10 host := "smtp.163.com"
11 port := 465
12 email := "[email protected]"
13 password := "password"
14 toEmail := "[email protected]"
15 header := make(map[string]string)
16 header["From"] = "test" + ""
17 header["To"] = toEmail
18 header["Subject"] = "邮件标题"
19 header["Content-Type"] = "text/html; charset=UTF-8"
20 body := "我是一封电子邮件!golang发出. by:www.361way.com "
21 message := ""
22 for k, v := range header {
23 message += fmt.Sprintf("%s: %s\r\n", k, v)
24 }
25 message += "\r\n" + body
26 auth := smtp.PlainAuth(
27 "",
28 email,
29 password,
30 host,
31 )
32 err := SendMailUsingTLS(
33 fmt.Sprintf("%s:%d", host, port),
34 auth,
35 email,
36 []string{toEmail},
37 []byte(message),
38 )
39 if err != nil {
40 panic(err)
41 }
42}
43//return a smtp client
44func Dial(addr string) (*smtp.Client, error) {
45 conn, err := tls.Dial("tcp", addr, nil)
46 if err != nil {
47 log.Println("Dialing Error:", err)
48 return nil, err
49 }
50 //分解主机端口字符串
51 host, _, _ := net.SplitHostPort(addr)
52 return smtp.NewClient(conn, host)
53}
54//参考net/smtp的func SendMail()
55//使用net.Dial连接tls(ssl)端口时,smtp.NewClient()会卡住且不提示err
56//len(to)>1时,to[1]开始提示是密送
57func SendMailUsingTLS(addr string, auth smtp.Auth, from string,
58 to []string, msg []byte) (err error) {
59 //create smtp client
60 c, err := Dial(addr)
61 if err != nil {
62 log.Println("Create smpt client error:", err)
63 return err
64 }
65 defer c.Close()
66 if auth != nil {
67 if ok, _ := c.Extension("AUTH"); ok {
68 if err = c.Auth(auth); err != nil {
69 log.Println("Error during AUTH", err)
70 return err
71 }
72 }
73 }
74 if err = c.Mail(from); err != nil {
75 return err
76 }
77 for _, addr := range to {
78 if err = c.Rcpt(addr); err != nil {
79 return err
80 }
81 }
82 w, err := c.Data()
83 if err != nil {
84 return err
85 }
86 _, err = w.Write(msg)
87 if err != nil {
88 return err
89 }
90 err = w.Close()
91 if err != nil {
92 return err
93 }
94 return c.Quit()
95}
调用后,邮件发送示例如下:
由于上面header里,from里的名称是test,所以上图中可以看出,发件中显示的就是test,就里可以根据自己的需要进行修改。
三、发送html格式的邮件
如果发送的格式,想要比较丰富,就需要使用html格式的body进行发送,具体示例如下:
1package main
2import (
3 "fmt"
4 "net/smtp"
5 "strings"
6)
7func SendToMail(user, password, host, to, subject, body, mailtype string) error {
8 hp := strings.Split(host, ":")
9 auth := smtp.PlainAuth("", user, password, hp[0])
10 var content_type string
11 if mailtype == "html" {
12 content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
13 } else {
14 content_type = "Content-Type: text/plain" + "; charset=UTF-8"
15 }
16 msg := []byte("To: " + to + "\r\nFrom: " + user + ">\r\nSubject: " + "\r\n" + content_type + "\r\n\r\n" + body)
17 send_to := strings.Split(to, ";")
18 err := smtp.SendMail(host, auth, user, send_to, msg)
19 return err
20}
21func main() {
22 user := "yang**@yun*.com"
23 password := "***"
24 host := "smtp.exmail.qq.com:25"
25 to := "[email protected]"
26 subject := "使用Golang发送邮件"
27 body := `
28 <html>
29 <body>
30 <h3>
31 "Test send to email ,from www.361way.com"
32 </h3>
33 </body>
34 </html>
35 `
36 fmt.Println("send email")
37 err := SendToMail(user, password, host, to, subject, body, "html")
38 if err != nil {
39 fmt.Println("Send mail error!")
40 fmt.Println(err)
41 } else {
42 fmt.Println("Send mail success!")
43 }
44}
上面的send_to := strings.Split(to, “;”)是针对多个收件人时做的处理,而msg := []byte 是强制做了格式转换。
四、发送可自定义模板的邮件
一些网站需要通过自动邮件发送时,可以有多个模板可以选择,这里就可以使用”html/template”模块发送格式邮件,该html模板可以自定义修改,要一些变量引用的地方,以类似于jinja2的形式进行引用即可,go代码如下:
1package main
2import (
3 "bytes"
4 "fmt"
5 "html/template"
6 "net/smtp"
7)
8var auth smtp.Auth
9func main() {
10 auth = smtp.PlainAuth("", "[email protected]", "password", "smtp.gmail.com")
11 templateData := struct {
12 Name string
13 URL string
14 }{
15 Name: "myblog",
16 URL: "https://blog.361way.com",
17 }
18 r := NewRequest([]string{"[email protected]"}, "Hello Junk!", "Hello, World!")
19 err := r.ParseTemplate("template.html", templateData)
20 if err := r.ParseTemplate("template.html", templateData); err == nil {
21 ok, _ := r.SendEmail()
22 fmt.Println(ok)
23 }
24}
25//Request struct
26type Request struct {
27 from string
28 to []string
29 subject string
30 body string
31}
32func NewRequest(to []string, subject, body string) *Request {
33 return &Request{
34 to: to,
35 subject: subject,
36 body: body,
37 }
38}
39func (r *Request) SendEmail() (bool, error) {
40 mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
41 subject := "Subject: " + r.subject + "!\n"
42 msg := []byte(subject + mime + "\n" + r.body)
43 addr := "smtp.gmail.com:587"
44 if err := smtp.SendMail(addr, auth, "[email protected]", r.to, msg); err != nil {
45 return false, err
46 }
47 return true, nil
48}
49func (r *Request) ParseTemplate(templateFileName string, data interface{}) error {
50 t, err := template.ParseFiles(templateFileName)
51 if err != nil {
52 return err
53 }
54 buf := new(bytes.Buffer)
55 if err = t.Execute(buf, data); err != nil {
56 return err
57 }
58 r.body = buf.String()
59 return nil
60}
对应的模块文件内容如下(template.html):
<pre data-language="HTML">```markup
<html>
</head>
<body>
<p>
Hello {{.Name}}
<a href="{{.URL}}">Confirm you web address</a>
</p>
</body>
</html>
该模块文件使用的就是结构体templateData里的数据。
</body></html>
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/golang-send-email/5853.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.