Skip to content

Commit 5ceb8e6

Browse files
committed
Dialer.Dial() now automatically uses CRAM-MD5 when it's available
Also deprecated NewPlainDialer() in favor of NewDialer(). Fixes go-gomail#52
1 parent 6ea1c86 commit 5ceb8e6

File tree

6 files changed

+112
-219
lines changed

6 files changed

+112
-219
lines changed

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ bypass the verification of the server's certificate chain and host name by using
6060
)
6161

6262
func main() {
63-
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
63+
d := gomail.NewDialer("smtp.example.com", 587, "user", "123456")
6464
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
6565

6666
// Send emails using d.

Diff for: auth.go

+17-35
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,33 @@ import (
77
"net/smtp"
88
)
99

10-
// plainAuth is an smtp.Auth that implements the PLAIN authentication mechanism.
11-
// It fallbacks to the LOGIN mechanism if it is the only mechanism advertised
12-
// by the server.
13-
type plainAuth struct {
10+
// loginAuth is an smtp.Auth that implements the LOGIN authentication mechanism.
11+
type loginAuth struct {
1412
username string
1513
password string
1614
host string
17-
login bool
1815
}
1916

20-
func (a *plainAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
21-
if server.Name != a.host {
22-
return "", nil, errors.New("gomail: wrong host name")
23-
}
24-
25-
var plain, login bool
26-
for _, a := range server.Auth {
27-
switch a {
28-
case "PLAIN":
29-
plain = true
30-
case "LOGIN":
31-
login = true
17+
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
18+
if !server.TLS {
19+
advertised := false
20+
for _, mechanism := range server.Auth {
21+
if mechanism == "LOGIN" {
22+
advertised = true
23+
break
24+
}
25+
}
26+
if !advertised {
27+
return "", nil, errors.New("gomail: unencrypted connection")
3228
}
3329
}
34-
35-
if !server.TLS && !plain && !login {
36-
return "", nil, errors.New("gomail: unencrypted connection")
37-
}
38-
39-
if !plain && login {
40-
a.login = true
41-
return "LOGIN", nil, nil
30+
if server.Name != a.host {
31+
return "", nil, errors.New("gomail: wrong host name")
4232
}
43-
44-
return "PLAIN", []byte("\x00" + a.username + "\x00" + a.password), nil
33+
return "LOGIN", nil, nil
4534
}
4635

47-
func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) {
48-
if !a.login {
49-
if more {
50-
return nil, errors.New("gomail: unexpected server challenge")
51-
}
52-
return nil, nil
53-
}
54-
36+
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
5537
if !more {
5638
return nil, nil
5739
}

Diff for: auth_test.go

+16-72
Original file line numberDiff line numberDiff line change
@@ -11,103 +11,51 @@ const (
1111
testHost = "smtp.example.com"
1212
)
1313

14-
var testAuth = &plainAuth{
15-
username: testUser,
16-
password: testPwd,
17-
host: testHost,
18-
}
19-
20-
type plainAuthTest struct {
14+
type authTest struct {
2115
auths []string
2216
challenges []string
2317
tls bool
24-
wantProto string
2518
wantData []string
2619
wantError bool
2720
}
2821

2922
func TestNoAdvertisement(t *testing.T) {
30-
testPlainAuth(t, &plainAuthTest{
31-
auths: []string{},
32-
challenges: []string{"Username:", "Password:"},
33-
tls: false,
34-
wantProto: "PLAIN",
35-
wantError: true,
23+
testLoginAuth(t, &authTest{
24+
auths: []string{},
25+
tls: false,
26+
wantError: true,
3627
})
3728
}
3829

3930
func TestNoAdvertisementTLS(t *testing.T) {
40-
testPlainAuth(t, &plainAuthTest{
31+
testLoginAuth(t, &authTest{
4132
auths: []string{},
4233
challenges: []string{"Username:", "Password:"},
4334
tls: true,
44-
wantProto: "PLAIN",
45-
wantData: []string{"\x00" + testUser + "\x00" + testPwd},
46-
})
47-
}
48-
49-
func TestPlain(t *testing.T) {
50-
testPlainAuth(t, &plainAuthTest{
51-
auths: []string{"PLAIN"},
52-
challenges: []string{"Username:", "Password:"},
53-
tls: false,
54-
wantProto: "PLAIN",
55-
wantData: []string{"\x00" + testUser + "\x00" + testPwd},
56-
})
57-
}
58-
59-
func TestPlainTLS(t *testing.T) {
60-
testPlainAuth(t, &plainAuthTest{
61-
auths: []string{"PLAIN"},
62-
challenges: []string{"Username:", "Password:"},
63-
tls: true,
64-
wantProto: "PLAIN",
65-
wantData: []string{"\x00" + testUser + "\x00" + testPwd},
66-
})
67-
}
68-
69-
func TestPlainAndLogin(t *testing.T) {
70-
testPlainAuth(t, &plainAuthTest{
71-
auths: []string{"PLAIN", "LOGIN"},
72-
challenges: []string{"Username:", "Password:"},
73-
tls: false,
74-
wantProto: "PLAIN",
75-
wantData: []string{"\x00" + testUser + "\x00" + testPwd},
76-
})
77-
}
78-
79-
func TestPlainAndLoginTLS(t *testing.T) {
80-
testPlainAuth(t, &plainAuthTest{
81-
auths: []string{"PLAIN", "LOGIN"},
82-
challenges: []string{"Username:", "Password:"},
83-
tls: true,
84-
wantProto: "PLAIN",
85-
wantData: []string{"\x00" + testUser + "\x00" + testPwd},
35+
wantData: []string{"", testUser, testPwd},
8636
})
8737
}
8838

8939
func TestLogin(t *testing.T) {
90-
testPlainAuth(t, &plainAuthTest{
91-
auths: []string{"LOGIN"},
40+
testLoginAuth(t, &authTest{
41+
auths: []string{"PLAIN", "LOGIN"},
9242
challenges: []string{"Username:", "Password:"},
9343
tls: false,
94-
wantProto: "LOGIN",
9544
wantData: []string{"", testUser, testPwd},
9645
})
9746
}
9847

9948
func TestLoginTLS(t *testing.T) {
100-
testPlainAuth(t, &plainAuthTest{
49+
testLoginAuth(t, &authTest{
10150
auths: []string{"LOGIN"},
10251
challenges: []string{"Username:", "Password:"},
10352
tls: true,
104-
wantProto: "LOGIN",
10553
wantData: []string{"", testUser, testPwd},
10654
})
10755
}
10856

109-
func testPlainAuth(t *testing.T, test *plainAuthTest) {
110-
auth := &plainAuth{
57+
func testLoginAuth(t *testing.T, test *authTest) {
58+
auth := &loginAuth{
11159
username: testUser,
11260
password: testPwd,
11361
host: testHost,
@@ -119,13 +67,13 @@ func testPlainAuth(t *testing.T, test *plainAuthTest) {
11967
}
12068
proto, toServer, err := auth.Start(server)
12169
if err != nil && !test.wantError {
122-
t.Fatalf("plainAuth.Start(): %v", err)
70+
t.Fatalf("loginAuth.Start(): %v", err)
12371
}
12472
if err != nil && test.wantError {
12573
return
12674
}
127-
if proto != test.wantProto {
128-
t.Errorf("invalid protocol, got %q, want %q", proto, test.wantProto)
75+
if proto != "LOGIN" {
76+
t.Errorf("invalid protocol, got %q, want LOGIN", proto)
12977
}
13078

13179
i := 0
@@ -134,10 +82,6 @@ func testPlainAuth(t *testing.T, test *plainAuthTest) {
13482
t.Errorf("Invalid response, got %q, want %q", got, test.wantData[i])
13583
}
13684

137-
if proto == "PLAIN" {
138-
return
139-
}
140-
14185
for _, challenge := range test.challenges {
14286
i++
14387
if i >= len(test.wantData) {
@@ -146,7 +90,7 @@ func testPlainAuth(t *testing.T, test *plainAuthTest) {
14690

14791
toServer, err = auth.Next([]byte(challenge), true)
14892
if err != nil {
149-
t.Fatalf("plainAuth.Auth(): %v", err)
93+
t.Fatalf("loginAuth.Auth(): %v", err)
15094
}
15195
got = string(toServer)
15296
if got != test.wantData[i] {

Diff for: example_test.go

+3-22
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"html/template"
66
"io"
77
"log"
8-
"net/smtp"
98
"time"
109

1110
"gopkg.in/gomail.v2"
@@ -20,7 +19,7 @@ func Example() {
2019
m.SetBody("text/html", "Hello <b>Bob</b> and <i>Cora</i>!")
2120
m.Attach("/home/Alex/lolcat.jpg")
2221

23-
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
22+
d := gomail.NewDialer("smtp.example.com", 587, "user", "123456")
2423

2524
// Send the email to Bob, Cora and Dan.
2625
if err := d.DialAndSend(m); err != nil {
@@ -33,7 +32,7 @@ func Example_daemon() {
3332
ch := make(chan *gomail.Message)
3433

3534
go func() {
36-
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
35+
d := gomail.NewDialer("smtp.example.com", 587, "user", "123456")
3736

3837
var s gomail.SendCloser
3938
var err error
@@ -80,7 +79,7 @@ func Example_newsletter() {
8079
Address string
8180
}
8281

83-
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
82+
d := gomail.NewDialer("smtp.example.com", 587, "user", "123456")
8483
s, err := d.Dial()
8584
if err != nil {
8685
panic(err)
@@ -114,24 +113,6 @@ func Example_noAuth() {
114113
}
115114
}
116115

117-
// Send an email using the CRAM-MD5 authentication mechanism.
118-
func Example_cRAMMD5() {
119-
m := gomail.NewMessage()
120-
m.SetHeader("From", "[email protected]")
121-
m.SetHeader("To", "[email protected]")
122-
m.SetHeader("Subject", "Hello!")
123-
m.SetBody("text/plain", "Hello!")
124-
125-
d := gomail.Dialer{
126-
Host: "localhost",
127-
Port: 587,
128-
Auth: smtp.CRAMMD5Auth("username", "secret"),
129-
}
130-
if err := d.DialAndSend(m); err != nil {
131-
panic(err)
132-
}
133-
}
134-
135116
// Send an email using an API or postfix.
136117
func Example_noSMTP() {
137118
m := gomail.NewMessage()

0 commit comments

Comments
 (0)