正在显示
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 | +// } |
-
请 注册 或 登录 后发表评论