正在显示
4 个修改的文件
包含
166 行增加
和
63 行删除
goemail/auth.go
0 → 100644
| 1 | +package goemail | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "bytes" | ||
| 5 | + "errors" | ||
| 6 | + "fmt" | ||
| 7 | + "net/smtp" | ||
| 8 | +) | ||
| 9 | + | ||
| 10 | +//loginAuth实现smtp.Auth的接口,实现登录身份验证机制的验证. | ||
| 11 | +//扩展net/smtp中实现的认证机制,net/smtp中仅实现了PlainAuth和CRAMMD5Auth | ||
| 12 | +type loginAuth struct { | ||
| 13 | + username string | ||
| 14 | + password string | ||
| 15 | + host string | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +var _ smtp.Auth = &loginAuth{} | ||
| 19 | + | ||
| 20 | +func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) { | ||
| 21 | + if !server.TLS { | ||
| 22 | + advertised := false | ||
| 23 | + for _, mechanism := range server.Auth { | ||
| 24 | + if mechanism == "LOGIN" { | ||
| 25 | + advertised = true | ||
| 26 | + break | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | + if !advertised { | ||
| 30 | + return "", nil, errors.New("mail: unencrypted connection") | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + if server.Name != a.host { | ||
| 34 | + return "", nil, errors.New("mail: wrong host name") | ||
| 35 | + } | ||
| 36 | + return "LOGIN", nil, nil | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) { | ||
| 40 | + if !more { | ||
| 41 | + return nil, nil | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + switch { | ||
| 45 | + case bytes.Equal(fromServer, []byte("username:")): | ||
| 46 | + return []byte(a.username), nil | ||
| 47 | + case bytes.Equal(fromServer, []byte("Password:")): | ||
| 48 | + return []byte(a.password), nil | ||
| 49 | + default: | ||
| 50 | + return nil, fmt.Errorf("mail: unexpected server challenge: %s", fromServer) | ||
| 51 | + } | ||
| 52 | +} |
| 1 | package goemail | 1 | package goemail |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | - "bytes" | ||
| 5 | - "encoding/base64" | ||
| 6 | - "fmt" | ||
| 7 | "net/smtp" | 4 | "net/smtp" |
| 8 | - "strings" | ||
| 9 | - "time" | ||
| 10 | ) | 5 | ) |
| 11 | 6 | ||
| 12 | -type EmailHeader struct { | ||
| 13 | - Key string | ||
| 14 | - Value string | ||
| 15 | -} | ||
| 16 | - | ||
| 17 | -type EmailMessage struct { | ||
| 18 | - FromEmail string //发件人邮箱地址 | ||
| 19 | - Header []EmailHeader //TODO | ||
| 20 | - Toers []string //邮件接收人,如有多个,则以英文逗号(“,”)隔开,不能为空 | ||
| 21 | - Subject string //主题 | ||
| 22 | - BodyContentType string | ||
| 23 | - Body []byte //内容 | ||
| 24 | - //TODO Copyers []string //邮件抄送人,如有多个,则以英文逗号(“,”)隔开,不能为空 | ||
| 25 | - //TODO附加 | ||
| 26 | -} | 7 | +// ServerHost string //邮箱服务器地址 |
| 8 | +// ServerPort string //邮箱服务器的端口 | ||
| 9 | +// FromPasswd string //密码 | ||
| 27 | 10 | ||
| 28 | -func (e *EmailMessage) AddToer(v string) { | ||
| 29 | - e.Toers = append(e.Toers, v) | ||
| 30 | -} | ||
| 31 | - | ||
| 32 | -func (e *EmailMessage) SetBody(v []byte) { | ||
| 33 | - e.Body = v | ||
| 34 | -} | ||
| 35 | -func (e *EmailMessage) Bytes() []byte { | ||
| 36 | - buf := bytes.NewBuffer(nil) | ||
| 37 | - buf.WriteString(fmt.Sprintf("From:%s \r\n", e.FromEmail)) | ||
| 38 | - t := time.Now().Format(time.RFC1123Z) | ||
| 39 | - buf.WriteString(fmt.Sprintf("Date:%s \r\n", t)) | ||
| 40 | - buf.WriteString(fmt.Sprintf("To:%s \r\n", strings.Join(e.Toers, ","))) | ||
| 41 | - var subject = "=?UTF-8?B?" + base64.StdEncoding.EncodeToString([]byte(e.Subject)) + "?=" | ||
| 42 | - buf.WriteString("Subject: " + subject + "\r\n") | ||
| 43 | - buf.WriteString("MIME-Version: 1.0\r\n") | ||
| 44 | - //TODO 添加header | ||
| 45 | - boundary := "THIS_IS_BOUNDARY" | ||
| 46 | - buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n") | ||
| 47 | - buf.WriteString("\r\n--" + boundary + "\r\n") | ||
| 48 | - buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=utf-8\r\n\r\n", e.BodyContentType)) | ||
| 49 | - buf.Write(e.Body) | ||
| 50 | - buf.WriteString("\r\n") | ||
| 51 | - buf.WriteString("--" + boundary + "--") | ||
| 52 | - //TODO添加附件 | ||
| 53 | - return buf.Bytes() | ||
| 54 | -} | ||
| 55 | - | ||
| 56 | -// func (e *EmailMessage) To() []string { | ||
| 57 | -// return e.Toers | ||
| 58 | -// } | ||
| 59 | -func NewHtmlEmail() *EmailMessage { | ||
| 60 | - return nil | 11 | +//NewPlainAuth |
| 12 | +func NewPlainAuth(fromEmail string, pwd string, host string) smtp.Auth { | ||
| 13 | + return smtp.PlainAuth("", fromEmail, pwd, host) | ||
| 61 | } | 14 | } |
| 62 | 15 | ||
| 63 | -func (e *EmailMessage) AddHeader(key string, value string) EmailHeader { | ||
| 64 | - newHeader := EmailHeader{Key: key, Value: value} | ||
| 65 | - e.Header = append(e.Header, newHeader) | ||
| 66 | - return newHeader | 16 | +func NewLoginAuth(fromEmail string, pwd string, host string) smtp.Auth { |
| 17 | + return &loginAuth{ | ||
| 18 | + username: fromEmail, | ||
| 19 | + password: pwd, | ||
| 20 | + host: host, | ||
| 21 | + } | ||
| 67 | } | 22 | } |
| 68 | 23 | ||
| 69 | -// ServerHost string //邮箱服务器地址 | ||
| 70 | -// ServerPort int //邮箱服务器的端口 | ||
| 71 | -// FromPasswd string //发件人邮箱密码 | ||
| 72 | -func NewSmtpAuth(fromEmail string, pwd string, host string) smtp.Auth { | ||
| 73 | - return smtp.PlainAuth("", fromEmail, pwd, host) | ||
| 74 | -} | ||
| 75 | func Send(addr string, auth smtp.Auth, m *EmailMessage) error { | 24 | func Send(addr string, auth smtp.Auth, m *EmailMessage) error { |
| 76 | return smtp.SendMail(addr, auth, m.FromEmail, m.Toers, m.Bytes()) | 25 | return smtp.SendMail(addr, auth, m.FromEmail, m.Toers, m.Bytes()) |
| 77 | } | 26 | } |
goemail/email_test.go
0 → 100644
| 1 | +package goemail | ||
| 2 | + | ||
| 3 | +import "testing" | ||
| 4 | + | ||
| 5 | +const ( | ||
| 6 | + testTo1 = "554895468@qq.com" | ||
| 7 | + testTo2 = "to2@example.com" | ||
| 8 | + testFrom = "" | ||
| 9 | + testpwd = "" | ||
| 10 | + testBody = "Test message" | ||
| 11 | + testMsg = "To: " + testTo1 + ", " + testTo2 + "\r\n" + | ||
| 12 | + "From: " + testFrom + "\r\n" + | ||
| 13 | + "Mime-Version: 1.0\r\n" + | ||
| 14 | + "Date: Wed, 25 Jun 2014 17:46:00 +0000\r\n" + | ||
| 15 | + "Content-Type: text/plain; charset=UTF-8\r\n" + | ||
| 16 | + "Content-Transfer-Encoding: quoted-printable\r\n" + | ||
| 17 | + "\r\n" + | ||
| 18 | + testBody | ||
| 19 | +) | ||
| 20 | + | ||
| 21 | +func TestSend(T *testing.T) { | ||
| 22 | + m := &EmailMessage{ | ||
| 23 | + FromEmail: testFrom, | ||
| 24 | + Toers: []string{testTo1}, | ||
| 25 | + Subject: "测试邮件", | ||
| 26 | + BodyContentType: "text/html", | ||
| 27 | + Body: []byte(testBody), | ||
| 28 | + } | ||
| 29 | + auth := NewLoginAuth(testFrom, testpwd, "smtp.163.com") | ||
| 30 | + err := Send("smtp.163.com:25", auth, m) | ||
| 31 | + if err != nil { | ||
| 32 | + T.Error(err) | ||
| 33 | + } | ||
| 34 | +} |
goemail/message.go
0 → 100644
| 1 | +package goemail | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "bytes" | ||
| 5 | + "encoding/base64" | ||
| 6 | + "fmt" | ||
| 7 | + "strings" | ||
| 8 | + "time" | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +type EmailHeader struct { | ||
| 12 | + Key string | ||
| 13 | + Value string | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +type EmailMessage struct { | ||
| 17 | + FromEmail string //发件人邮箱地址 | ||
| 18 | + // Header []EmailHeader | ||
| 19 | + Toers []string //邮件接收人,如有多个,则以英文逗号(“,”)隔开,不能为空 | ||
| 20 | + Subject string //主题 | ||
| 21 | + BodyContentType string //默认值text/html | ||
| 22 | + BodyCharset string //字符编码设定默认utf-8 | ||
| 23 | + Body []byte //邮件正文内容 | ||
| 24 | + //TODO 添加附件 | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +func (e *EmailMessage) AddToer(v string) { | ||
| 28 | + e.Toers = append(e.Toers, v) | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +func (e *EmailMessage) SetBody(v []byte) { | ||
| 32 | + e.Body = v | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +func (e *EmailMessage) SetBodyContentType(v string) { | ||
| 36 | + e.BodyContentType = v | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +func (e *EmailMessage) SetBodyCharset(v string) { | ||
| 40 | + e.BodyCharset = v | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +func (e *EmailMessage) Bytes() []byte { | ||
| 44 | + buf := bytes.NewBuffer(nil) | ||
| 45 | + buf.WriteString(fmt.Sprintf("From:%s \r\n", e.FromEmail)) | ||
| 46 | + t := time.Now().Format(time.RFC1123Z) | ||
| 47 | + buf.WriteString(fmt.Sprintf("Date:%s \r\n", t)) | ||
| 48 | + buf.WriteString(fmt.Sprintf("To:%s \r\n", strings.Join(e.Toers, ","))) | ||
| 49 | + var subject = "=?UTF-8?B?" + base64.StdEncoding.EncodeToString([]byte(e.Subject)) + "?=" | ||
| 50 | + buf.WriteString("Subject: " + subject + "\r\n") | ||
| 51 | + buf.WriteString("MIME-Version: 1.0\r\n") | ||
| 52 | + //TODO 添加header | ||
| 53 | + boundary := "THIS_IS_BOUNDARY" | ||
| 54 | + buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n") | ||
| 55 | + buf.WriteString("\r\n--" + boundary + "\r\n") | ||
| 56 | + buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=%s\r\n\r\n", e.BodyContentType, e.BodyCharset)) | ||
| 57 | + buf.Write(e.Body) | ||
| 58 | + buf.WriteString("\r\n") | ||
| 59 | + buf.WriteString("--" + boundary + "--") | ||
| 60 | + //TODO添加附件 | ||
| 61 | + return buf.Bytes() | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +// func (e *EmailMessage) AddHeader(key string, value string) EmailHeader { | ||
| 65 | +// newHeader := EmailHeader{Key: key, Value: value} | ||
| 66 | +// e.Header = append(e.Header, newHeader) | ||
| 67 | +// return newHeader | ||
| 68 | +// } |
-
请 注册 或 登录 后发表评论