|
|
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 |
...
|
...
|
|