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