作者 yangfu

mail

package common
import (
"bytes"
"crypto/tls"
"fmt"
"log"
"mime"
"net"
"net/smtp"
)
var(
ErrorInvalidMailConfig = fmt.Errorf("mail config error")
)
var DefaultMail *MailService
//邮件配置
type MailConfig struct {
Host string
Port int
From string
Password string
IsUseSsl bool
}
//初始化邮件服务
func InitMailService(mail *MailConfig){
DefaultMail = NewMailService(mail)
}
type MailService struct {
Config *MailConfig
}
func NewMailService(config *MailConfig)*MailService{
return &MailService{
Config:config,
}
}
//to: 邮件发送目标 多个
func (mail *MailService)SendMail(to []string, subject string, body []byte)(err error){
if err =mail.CheckConfig();err!=nil{
return
}
address :=fmt.Sprintf("%v:%v",mail.Config.Host,mail.Config.Port)
auth := smtp.PlainAuth("", mail.Config.From, mail.Config.Password, mail.Config.Host)
if !mail.Config.IsUseSsl{ //qq 普通发送 端口25
// hostname is used by PlainAuth to validate the TLS certificate.
err = smtp.SendMail(address, auth, mail.Config.From,to, body)
if err != nil {
return err
}
return
}
if err=SendMailUsingTLS(address, auth, mail.Config.From,to, body);err!=nil{
return
}
return
}
//检查配置
func(mail *MailService)CheckConfig()error{
config :=mail.Config
if len(config.Host)==0 || len(config.From)==0 || config.Port==0 || len(config.Password)==0{
return ErrorInvalidMailConfig
}
return nil
}
//邮件内容
type MailContent struct {
ToMail string
Subject string
Body []byte
ContentType string //html /plain
}
//发送邮件
func SendMail(content *MailContent)(err error){
if DefaultMail==nil{
return ErrorInvalidMailConfig
}
var to,subject,contentType string
var body []byte
to = content.ToMail
subject = content.Subject
contentType = content.ContentType
if contentType==""{
contentType="text/html; charset=UTF-8"
}
header :=make(map[string]string)
header["From"] = mime.BEncoding.Encode("utf-8",DefaultMail.Config.From) //from 使用其他字符串,显示xx发送 代发为 DefaultMail.Config.From
header["To"] = to
header["Subject"] = mime.BEncoding.Encode("utf-8",subject)
header["Content-Type"] = contentType
var buf bytes.Buffer
for k, v := range header {
buf.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
}
buf.WriteString("\r\n")
buf.Write(body)
return DefaultMail.SendMail([]string{to},subject,buf.Bytes())
}
//使用 ssl发送 端口465
//return a smtp client
func Dial(addr string) (*smtp.Client, error) {
conn, err := tls.Dial("tcp", addr, nil)
if err != nil {
log.Panicln("Dialing Error:", err)
return nil, err
}
//分解主机端口字符串
host, _, _ := net.SplitHostPort(addr)
return smtp.NewClient(conn, host)
}
//参考net/smtp的func SendMail()
//使用net.Dial连接tls(ssl)端口时,smtp.NewClient()会卡住且不提示err
//len(to)>1时,to[1]开始提示是密送
func SendMailUsingTLS(addr string, auth smtp.Auth, from string,
to []string, msg []byte) (err error) {
//create smtp client
c, err := Dial(addr)
if err != nil {
log.Println("Create smpt client error:", err)
return err
}
defer c.Close()
if auth != nil {
if ok, _ := c.Extension("AUTH"); ok {
if err = c.Auth(auth); err != nil {
log.Println("Error during AUTH", err)
return err
}
}
}
if err = c.Mail(from); err != nil {
return err
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return c.Quit()
}
\ No newline at end of file
... ...
package common
import (
"testing"
)
//Example
func TestSendMail(t *testing.T) {
InitMailService(&MailConfig{
Host:"smtp.qq.com",
Port:25,
From:"785410885@qq.com",
Password:"ibfduqhfmgypbffe", //授权码
IsUseSsl:false,
})
//SendMail(&MailContent{
// ToMail:"892423867@qq.com",
// Subject:"测试邮件",
// Body:[]byte("邮件内容..."),
//})
}
func TestSendMailTls(t *testing.T) {
InitMailService(&MailConfig{
Host:"smtp.qq.com",
Port:465,
From:"785410885@qq.com",
Password:"ibfduqhfmgypbffe", //授权码
IsUseSsl:true,
})
//SendMail("892423867@qq.com","测试邮件",[]byte("邮件内容..."))
//SendMail(&MailContent{
// ToMail:"892423867@qq.com",
// Subject:"测试邮件",
// Body:[]byte("邮件内容..."),
//})
}
... ...