作者 yangfu

mail

  1 +package common
  2 +
  3 +import (
  4 + "bytes"
  5 + "crypto/tls"
  6 + "fmt"
  7 + "log"
  8 + "mime"
  9 + "net"
  10 + "net/smtp"
  11 +)
  12 +
  13 +var(
  14 + ErrorInvalidMailConfig = fmt.Errorf("mail config error")
  15 +)
  16 +
  17 +var DefaultMail *MailService
  18 +//邮件配置
  19 +type MailConfig struct {
  20 + Host string
  21 + Port int
  22 + From string
  23 + Password string
  24 + IsUseSsl bool
  25 +}
  26 +
  27 +//初始化邮件服务
  28 +func InitMailService(mail *MailConfig){
  29 + DefaultMail = NewMailService(mail)
  30 +}
  31 +type MailService struct {
  32 + Config *MailConfig
  33 +}
  34 +func NewMailService(config *MailConfig)*MailService{
  35 + return &MailService{
  36 + Config:config,
  37 + }
  38 +}
  39 +//to: 邮件发送目标 多个
  40 +func (mail *MailService)SendMail(to []string, subject string, body []byte)(err error){
  41 + if err =mail.CheckConfig();err!=nil{
  42 + return
  43 + }
  44 + address :=fmt.Sprintf("%v:%v",mail.Config.Host,mail.Config.Port)
  45 + auth := smtp.PlainAuth("", mail.Config.From, mail.Config.Password, mail.Config.Host)
  46 + if !mail.Config.IsUseSsl{ //qq 普通发送 端口25
  47 + // hostname is used by PlainAuth to validate the TLS certificate.
  48 + err = smtp.SendMail(address, auth, mail.Config.From,to, body)
  49 + if err != nil {
  50 + return err
  51 + }
  52 + return
  53 + }
  54 + if err=SendMailUsingTLS(address, auth, mail.Config.From,to, body);err!=nil{
  55 + return
  56 + }
  57 + return
  58 +}
  59 +//检查配置
  60 +func(mail *MailService)CheckConfig()error{
  61 + config :=mail.Config
  62 + if len(config.Host)==0 || len(config.From)==0 || config.Port==0 || len(config.Password)==0{
  63 + return ErrorInvalidMailConfig
  64 + }
  65 + return nil
  66 +}
  67 +
  68 +//邮件内容
  69 +type MailContent struct {
  70 + ToMail string
  71 + Subject string
  72 + Body []byte
  73 + ContentType string //html /plain
  74 +}
  75 +//发送邮件
  76 +func SendMail(content *MailContent)(err error){
  77 + if DefaultMail==nil{
  78 + return ErrorInvalidMailConfig
  79 + }
  80 + var to,subject,contentType string
  81 + var body []byte
  82 + to = content.ToMail
  83 + subject = content.Subject
  84 + contentType = content.ContentType
  85 + if contentType==""{
  86 + contentType="text/html; charset=UTF-8"
  87 + }
  88 + header :=make(map[string]string)
  89 + header["From"] = mime.BEncoding.Encode("utf-8",DefaultMail.Config.From) //from 使用其他字符串,显示xx发送 代发为 DefaultMail.Config.From
  90 + header["To"] = to
  91 + header["Subject"] = mime.BEncoding.Encode("utf-8",subject)
  92 + header["Content-Type"] = contentType
  93 + var buf bytes.Buffer
  94 + for k, v := range header {
  95 + buf.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
  96 + }
  97 + buf.WriteString("\r\n")
  98 + buf.Write(body)
  99 + return DefaultMail.SendMail([]string{to},subject,buf.Bytes())
  100 +}
  101 +//使用 ssl发送 端口465
  102 +//return a smtp client
  103 +func Dial(addr string) (*smtp.Client, error) {
  104 + conn, err := tls.Dial("tcp", addr, nil)
  105 + if err != nil {
  106 + log.Panicln("Dialing Error:", err)
  107 + return nil, err
  108 + }
  109 + //分解主机端口字符串
  110 + host, _, _ := net.SplitHostPort(addr)
  111 + return smtp.NewClient(conn, host)
  112 +}
  113 +//参考net/smtp的func SendMail()
  114 +//使用net.Dial连接tls(ssl)端口时,smtp.NewClient()会卡住且不提示err
  115 +//len(to)>1时,to[1]开始提示是密送
  116 +func SendMailUsingTLS(addr string, auth smtp.Auth, from string,
  117 + to []string, msg []byte) (err error) {
  118 +
  119 + //create smtp client
  120 + c, err := Dial(addr)
  121 + if err != nil {
  122 + log.Println("Create smpt client error:", err)
  123 + return err
  124 + }
  125 + defer c.Close()
  126 +
  127 + if auth != nil {
  128 + if ok, _ := c.Extension("AUTH"); ok {
  129 + if err = c.Auth(auth); err != nil {
  130 + log.Println("Error during AUTH", err)
  131 + return err
  132 + }
  133 + }
  134 + }
  135 +
  136 + if err = c.Mail(from); err != nil {
  137 + return err
  138 + }
  139 +
  140 + for _, addr := range to {
  141 + if err = c.Rcpt(addr); err != nil {
  142 + return err
  143 + }
  144 + }
  145 +
  146 + w, err := c.Data()
  147 + if err != nil {
  148 + return err
  149 + }
  150 +
  151 + _, err = w.Write(msg)
  152 + if err != nil {
  153 + return err
  154 + }
  155 +
  156 + err = w.Close()
  157 + if err != nil {
  158 + return err
  159 + }
  160 + return c.Quit()
  161 +}
  1 +package common
  2 +
  3 +import (
  4 + "testing"
  5 +)
  6 +
  7 +//Example
  8 +func TestSendMail(t *testing.T) {
  9 + InitMailService(&MailConfig{
  10 + Host:"smtp.qq.com",
  11 + Port:25,
  12 + From:"785410885@qq.com",
  13 + Password:"ibfduqhfmgypbffe", //授权码
  14 + IsUseSsl:false,
  15 + })
  16 + //SendMail(&MailContent{
  17 + // ToMail:"892423867@qq.com",
  18 + // Subject:"测试邮件",
  19 + // Body:[]byte("邮件内容..."),
  20 + //})
  21 +}
  22 +
  23 +func TestSendMailTls(t *testing.T) {
  24 + InitMailService(&MailConfig{
  25 + Host:"smtp.qq.com",
  26 + Port:465,
  27 + From:"785410885@qq.com",
  28 + Password:"ibfduqhfmgypbffe", //授权码
  29 + IsUseSsl:true,
  30 + })
  31 + //SendMail("892423867@qq.com","测试邮件",[]byte("邮件内容..."))
  32 + //SendMail(&MailContent{
  33 + // ToMail:"892423867@qq.com",
  34 + // Subject:"测试邮件",
  35 + // Body:[]byte("邮件内容..."),
  36 + //})
  37 +}