作者 唐旭辉

邮件基本包

package goemail
import (
"bytes"
"errors"
"fmt"
"net/smtp"
)
//loginAuth实现smtp.Auth的接口,实现登录身份验证机制的验证.
//扩展net/smtp中实现的认证机制,net/smtp中仅实现了PlainAuth和CRAMMD5Auth
type loginAuth struct {
username string
password string
host string
}
var _ smtp.Auth = &loginAuth{}
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
if !server.TLS {
advertised := false
for _, mechanism := range server.Auth {
if mechanism == "LOGIN" {
advertised = true
break
}
}
if !advertised {
return "", nil, errors.New("mail: unencrypted connection")
}
}
if server.Name != a.host {
return "", nil, errors.New("mail: wrong host name")
}
return "LOGIN", nil, nil
}
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if !more {
return nil, nil
}
switch {
case bytes.Equal(fromServer, []byte("username:")):
return []byte(a.username), nil
case bytes.Equal(fromServer, []byte("Password:")):
return []byte(a.password), nil
default:
return nil, fmt.Errorf("mail: unexpected server challenge: %s", fromServer)
}
}
... ...
package goemail
import (
"bytes"
"encoding/base64"
"fmt"
"net/smtp"
"strings"
"time"
)
type EmailHeader struct {
Key string
Value string
}
type EmailMessage struct {
FromEmail string //发件人邮箱地址
Header []EmailHeader //TODO
Toers []string //邮件接收人,如有多个,则以英文逗号(“,”)隔开,不能为空
Subject string //主题
BodyContentType string
Body []byte //内容
//TODO Copyers []string //邮件抄送人,如有多个,则以英文逗号(“,”)隔开,不能为空
//TODO附加
}
func (e *EmailMessage) AddToer(v string) {
e.Toers = append(e.Toers, v)
}
func (e *EmailMessage) SetBody(v []byte) {
e.Body = v
}
func (e *EmailMessage) Bytes() []byte {
buf := bytes.NewBuffer(nil)
buf.WriteString(fmt.Sprintf("From:%s \r\n", e.FromEmail))
t := time.Now().Format(time.RFC1123Z)
buf.WriteString(fmt.Sprintf("Date:%s \r\n", t))
buf.WriteString(fmt.Sprintf("To:%s \r\n", strings.Join(e.Toers, ",")))
var subject = "=?UTF-8?B?" + base64.StdEncoding.EncodeToString([]byte(e.Subject)) + "?="
buf.WriteString("Subject: " + subject + "\r\n")
buf.WriteString("MIME-Version: 1.0\r\n")
//TODO 添加header
boundary := "THIS_IS_BOUNDARY"
buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n")
buf.WriteString("\r\n--" + boundary + "\r\n")
buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=utf-8\r\n\r\n", e.BodyContentType))
buf.Write(e.Body)
buf.WriteString("\r\n")
buf.WriteString("--" + boundary + "--")
//TODO添加附件
return buf.Bytes()
}
// ServerHost string //邮箱服务器地址
// ServerPort string //邮箱服务器的端口
// FromPasswd string //密码
// func (e *EmailMessage) To() []string {
// return e.Toers
// }
func NewHtmlEmail() *EmailMessage {
return nil
//NewPlainAuth
func NewPlainAuth(fromEmail string, pwd string, host string) smtp.Auth {
return smtp.PlainAuth("", fromEmail, pwd, host)
}
func (e *EmailMessage) AddHeader(key string, value string) EmailHeader {
newHeader := EmailHeader{Key: key, Value: value}
e.Header = append(e.Header, newHeader)
return newHeader
func NewLoginAuth(fromEmail string, pwd string, host string) smtp.Auth {
return &loginAuth{
username: fromEmail,
password: pwd,
host: host,
}
}
// ServerHost string //邮箱服务器地址
// ServerPort int //邮箱服务器的端口
// FromPasswd string //发件人邮箱密码
func NewSmtpAuth(fromEmail string, pwd string, host string) smtp.Auth {
return smtp.PlainAuth("", fromEmail, pwd, host)
}
func Send(addr string, auth smtp.Auth, m *EmailMessage) error {
return smtp.SendMail(addr, auth, m.FromEmail, m.Toers, m.Bytes())
}
... ...
package goemail
import "testing"
const (
testTo1 = "554895468@qq.com"
testTo2 = "to2@example.com"
testFrom = ""
testpwd = ""
testBody = "Test message"
testMsg = "To: " + testTo1 + ", " + testTo2 + "\r\n" +
"From: " + testFrom + "\r\n" +
"Mime-Version: 1.0\r\n" +
"Date: Wed, 25 Jun 2014 17:46:00 +0000\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"Content-Transfer-Encoding: quoted-printable\r\n" +
"\r\n" +
testBody
)
func TestSend(T *testing.T) {
m := &EmailMessage{
FromEmail: testFrom,
Toers: []string{testTo1},
Subject: "测试邮件",
BodyContentType: "text/html",
Body: []byte(testBody),
}
auth := NewLoginAuth(testFrom, testpwd, "smtp.163.com")
err := Send("smtp.163.com:25", auth, m)
if err != nil {
T.Error(err)
}
}
... ...
package goemail
import (
"bytes"
"encoding/base64"
"fmt"
"strings"
"time"
)
type EmailHeader struct {
Key string
Value string
}
type EmailMessage struct {
FromEmail string //发件人邮箱地址
// Header []EmailHeader
Toers []string //邮件接收人,如有多个,则以英文逗号(“,”)隔开,不能为空
Subject string //主题
BodyContentType string //默认值text/html
BodyCharset string //字符编码设定默认utf-8
Body []byte //邮件正文内容
//TODO 添加附件
}
func (e *EmailMessage) AddToer(v string) {
e.Toers = append(e.Toers, v)
}
func (e *EmailMessage) SetBody(v []byte) {
e.Body = v
}
func (e *EmailMessage) SetBodyContentType(v string) {
e.BodyContentType = v
}
func (e *EmailMessage) SetBodyCharset(v string) {
e.BodyCharset = v
}
func (e *EmailMessage) Bytes() []byte {
buf := bytes.NewBuffer(nil)
buf.WriteString(fmt.Sprintf("From:%s \r\n", e.FromEmail))
t := time.Now().Format(time.RFC1123Z)
buf.WriteString(fmt.Sprintf("Date:%s \r\n", t))
buf.WriteString(fmt.Sprintf("To:%s \r\n", strings.Join(e.Toers, ",")))
var subject = "=?UTF-8?B?" + base64.StdEncoding.EncodeToString([]byte(e.Subject)) + "?="
buf.WriteString("Subject: " + subject + "\r\n")
buf.WriteString("MIME-Version: 1.0\r\n")
//TODO 添加header
boundary := "THIS_IS_BOUNDARY"
buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n")
buf.WriteString("\r\n--" + boundary + "\r\n")
buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=%s\r\n\r\n", e.BodyContentType, e.BodyCharset))
buf.Write(e.Body)
buf.WriteString("\r\n")
buf.WriteString("--" + boundary + "--")
//TODO添加附件
return buf.Bytes()
}
// func (e *EmailMessage) AddHeader(key string, value string) EmailHeader {
// newHeader := EmailHeader{Key: key, Value: value}
// e.Header = append(e.Header, newHeader)
// return newHeader
// }
... ...