📌Golang📌应用📌smtp发送邮件.txt
"net/smtp"包实现了简单邮件传输协议(SMTP),包已冻结不再接受新功能。
func CRAMMD5Auth(username, secret string) Auth
返回一个实现了CRAM-MD5身份认证机制(参见RFC-2195)的Auth接口。
返回的接口使用给出的用户名和密码,采用响应——回答机制与服务端进行身份认证。
func PlainAuth(identity, username, password, host string) Auth
返回一个实现了PLAIN身份认证机制(参见RFC-4616)的Auth接口。
返回的接口使用给出的用户名和密码,通过TLS连接到主机认证,
采用identity为身份管理和行动(通常应设identity为"",以便使用username为身份)。
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error
SendMail连接到addr指定的服务器;如果支持会开启TLS;如果支持会使用a认证身份;
然后以from为邮件源地址发送邮件msg到目标地址to。(可以是多个目标地址:群发)
func NewClient(conn net.Conn, host string) (*Client, error)
使用已经存在的连接conn和作为服务器名的host(用于身份认证)来创建一个*Client
func Dial(addr string) (*Client, error)
返回一个连接到地址为addr的SMTP服务器的*Client;addr必须包含端口号。
func (c *Client) Extension(ext string) (bool, string)
返回服务端是否支持某个扩展,扩展名是大小写不敏感的。
如果扩展被支持,方法还会返回一个包含指定给该扩展的各个参数的字符串。
例如 c.Extension("AUTH")
smtp.qq.com 支持的授权方式有: LOGIN PLAIN XOAUTH XOAUTH2
smtpdm.aliyun.com 支持的授权方式有: PLAIN LOGIN XALIOAUTH
func (c *Client) Auth(a Auth) error
使用提供的认证机制进行认证。失败的认证会关闭该连接。
只有服务端支持AUTH时,本方法才有效。(但是不支持时,调用会默默的成功)
func (c *Client) StartTLS(config *tls.Config) error
发送STARTTLS命令,并将之后的所有数据往来加密。
只有服务器附加了STARTTLS扩展,这个方法才有效。
func (c *Client) Mail(from string) error
发送MAIL命令和邮箱地址from到服务器。
如果服务端支持8BITMIME扩展,本方法会添加BODY=8BITMIME参数。
方法初始化一次邮件传输,后应跟1到多个Rcpt方法的调用。
func (c *Client) Rcpt(to string) error
发送RCPT命令和邮箱地址to到服务器。
调用Rcpt方法之前必须调用了Mail方法,之后可以再一次调用Rcpt方法,也可以调用Data方法。
func (c *Client) Data() (io.WriteCloser, error)
发送DATA指令到服务器并返回一个io.WriteCloser,用于写入邮件信息。
调用者必须在调用c的下一个方法之前关闭这个io.WriteCloser。
方法必须在一次或多次Rcpt方法之后调用。
func (c *Client) Reset() error
向服务端发送REST命令,中断当前的邮件传输。
func (c *Client) Close() error
关闭连接。
func (c *Client) Quit() error
发送QUIT命令并关闭到服务端的连接。
========== ========== ========== ========== ==========
package email
import (
"bytes"
"net"
"net/smtp"
"slices"
"strings"
"time"
)
type Email interface {
Send(*SendArgs) error
}
type email struct {
addr string
user string
auth smtp.Auth
}
type Config struct {
Host string // eg: smtp.qq.com
Port string // 通常为25(普通)、465(TLS)
User string // eg: test.message@foxmail.com
Pwd string // PLAIN 授权码
Secret string // CRAM-MD5 密钥
}
func New(cfg *Config) Email {
var auth smtp.Auth
if cfg.Pwd != "" {
auth = smtp.PlainAuth("", cfg.User, cfg.Pwd, cfg.Host)
} else {
auth = smtp.CRAMMD5Auth(cfg.User, cfg.Secret)
}
return &email{
addr: net.JoinHostPort(cfg.Host, cfg.Port),
user: cfg.User,
auth: auth,
}
}
const (
br = "\r\n"
plainType = "Content-Type: text/plain; charset=UTF-8"
htmlType = "Content-Type: text/html; charset=UTF-8"
)
type SendArgs struct {
Subject string // 邮件标题
FromName string // 发件人别名(非邮箱格式),为空默认显示成邮箱用户名
ReplyTo string // 回复邮箱,点击回复自动填入收件人的邮箱账号
To []string // 收件邮箱
Cc []string // 抄送邮箱
Bcc []string // 密送邮箱
IsHtml bool // 是否为html模板
Body []byte // 邮件正文
}
func (e *email) Send(args *SendArgs) error {
buf := bytes.NewBuffer(nil)
buf.WriteString("Date: ")
buf.WriteString(time.Now().Format(time.RFC1123Z))
buf.WriteString(br)
buf.WriteString("Subject: ")
buf.WriteString(args.Subject)
buf.WriteString(br)
from := e.user
if args.FromName != "" {
from = args.FromName + " <" + e.user + ">"
}
buf.WriteString("From: ")
buf.WriteString(from)
buf.WriteString(br)
if args.ReplyTo != "" {
buf.WriteString("Reply-To: ")
buf.WriteString(args.ReplyTo)
buf.WriteString(br)
}
buf.WriteString("To: ")
buf.WriteString(strings.Join(args.To, ";"))
buf.WriteString(br)
if len(args.Cc) > 0 {
buf.WriteString("Cc: ")
buf.WriteString(strings.Join(args.Cc, ";"))
buf.WriteString(br)
}
bodyType := plainType
if args.IsHtml {
bodyType = htmlType
}
buf.WriteString(bodyType)
buf.WriteString(br)
buf.WriteString(br) // body和head之间必须空一行
buf.Write(args.Body)
return smtp.SendMail(e.addr, e.auth, e.user, slices.Concat(args.To, args.Cc, args.Bcc), buf.Bytes())
}
========== ========== ========== ========== ==========
func main() {
e := email.New(&email.Config{
Host: "smtp.qq.com",
Port: "587",
User: "service@foxmail.com",
Pwd: "ebnxxxxxxxxxxxehc",
Secret: "",
})
err := e.Send(&email.SendArgs{
Subject: "您有新的工单待处理",
FromName: "系统通知助手",
ReplyTo: "no-reply@foxmail.com",
To: []string{"xxxxxx@126.com", "xxxxxx@163.com"},
Cc: []string{"xxxxxx@qq.com", "xxxxxx@foxmail.com"},
Bcc: []string{"xxxxxx@vip.qq.com", "xxxxxx@gmail.com"},
IsHtml: false,
Body: []byte("这里是邮件正文内容"),
})
log.Println(err)
}
========== ========== 使用gomail包 ========== ==========
import (
"gopkg.in/gomail.v2"
"io"
"log"
)
func GomailExample() {
m := gomail.NewMessage()
m.SetHeader("Subject", "您有新的工单待处理")
m.SetHeader("From", "service@foxmail.com") // 必填且必须和账号名相同
m.SetHeader("Reply-To", "no-reply@foxmail.com")
m.SetHeader("To", "xxxxxx@126.com", "xxxxxx@163.com")
m.SetHeader("Cc", "xxxxxx@qq.com", "xxxxxx@foxmail.com")
m.SetHeader("Bcc", "xxxxxx@vip.qq.com", "xxxxxx@gmail.com")
m.SetBody("text/plain", "这里是邮件正文内容")
m.Attach("f1.txt", gomail.SetCopyFunc(func(w io.Writer) error {
_, err := w.Write([]byte("hello one."))
return err
}))
m.Attach("f2.txt", gomail.SetCopyFunc(func(w io.Writer) error {
_, err := w.Write([]byte("hello two."))
return err
}))
d := gomail.NewDialer("smtp.qq.com", 587, "service@foxmail.com", "ebnxxxxxxxxxxxehc")
err := d.DialAndSend(m)
log.Println(err)
}