diff options
author | Christopher Speller <crspeller@gmail.com> | 2017-08-17 17:19:06 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-17 17:19:06 -0700 |
commit | 96eab1202717e073782ec399a4e0820cae15b1bb (patch) | |
tree | 011012982be971c7e9ef91466f026bc0956ac9a2 /vendor/gopkg.in/gomail.v2 | |
parent | 2c895ee66eed626721135acfcc48254c6e3f3b29 (diff) | |
download | chat-96eab1202717e073782ec399a4e0820cae15b1bb.tar.gz chat-96eab1202717e073782ec399a4e0820cae15b1bb.tar.bz2 chat-96eab1202717e073782ec399a4e0820cae15b1bb.zip |
Updating server dependancies. (#7246)
Diffstat (limited to 'vendor/gopkg.in/gomail.v2')
-rw-r--r-- | vendor/gopkg.in/gomail.v2/.travis.yml | 1 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/README.md | 43 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/auth.go | 52 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/auth_test.go | 88 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/example_test.go | 14 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/message.go | 96 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/message_test.go | 177 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/mime.go | 6 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/mime_go14.go | 13 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/send.go | 11 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/smtp.go | 125 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/smtp_test.go | 118 | ||||
-rw-r--r-- | vendor/gopkg.in/gomail.v2/writeto.go | 96 |
13 files changed, 318 insertions, 522 deletions
diff --git a/vendor/gopkg.in/gomail.v2/.travis.yml b/vendor/gopkg.in/gomail.v2/.travis.yml index 48915e737..24edf22cc 100644 --- a/vendor/gopkg.in/gomail.v2/.travis.yml +++ b/vendor/gopkg.in/gomail.v2/.travis.yml @@ -5,5 +5,4 @@ go: - 1.3 - 1.4 - 1.5 - - 1.6 - tip diff --git a/vendor/gopkg.in/gomail.v2/README.md b/vendor/gopkg.in/gomail.v2/README.md index b3be9e146..18cb88130 100644 --- a/vendor/gopkg.in/gomail.v2/README.md +++ b/vendor/gopkg.in/gomail.v2/README.md @@ -6,12 +6,8 @@ Gomail is a simple and efficient package to send emails. It is well tested and documented. -Gomail can only send emails using an SMTP server. But the API is flexible and it -is easy to implement other methods for sending emails using a local Postfix, an -API, etc. - It is versioned using [gopkg.in](https://gopkg.in) so I promise -there will never be backward incompatible changes within each version. +they will never be backward incompatible changes within each version. It requires Go 1.2 or newer. With Go 1.5, no external dependencies are used. @@ -25,6 +21,7 @@ Gomail supports: - Automatic encoding of special characters - SSL and TLS - Sending multiple emails with the same SMTP connection +- Any method to send emails: SMTP, postfix (not included but easily doable), etc ## Documentation @@ -51,20 +48,8 @@ considered valid by the client running Gomail. As a quick workaround you can bypass the verification of the server's certificate chain and host name by using `SetTLSConfig`: - package main - - import ( - "crypto/tls" - - "gopkg.in/gomail.v2" - ) - - func main() { - d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") - d.TLSConfig = &tls.Config{InsecureSkipVerify: true} - - // Send emails using d. - } + d := gomail.NewPlainDialer("smtp.example.com", "user", "123456", 587) + d.TLSConfig = &tls.Config{InsecureSkipVerify: true} Note, however, that this is insecure and should not be used in production. @@ -90,3 +75,23 @@ See [CHANGELOG.md](CHANGELOG.md). You can ask questions on the [Gomail thread](https://groups.google.com/d/topic/golang-nuts/jMxZHzvvEVg/discussion) in the Go mailing-list. + + +## Support + +If you want to support the development of Gomail, I gladly accept donations. + +I will give 100% of the money I receive to +[Enfants, Espoir Du Monde](http://www.eedm.fr/). +EEDM is a French NGO which helps children in Bangladesh, Cameroun, Haiti, India +and Madagascar. + +All its members are volunteers so its operating costs are only +1.9%. So your money will directly helps children of these countries. + +As an added bonus, your donations will also tip me by lowering my taxes :smile: + +I will send an email with the receipt of the donation to EEDM annually to all +donors. + +[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PYQKC7VFVXCFG) diff --git a/vendor/gopkg.in/gomail.v2/auth.go b/vendor/gopkg.in/gomail.v2/auth.go index d28b83ab7..4bcdd0620 100644 --- a/vendor/gopkg.in/gomail.v2/auth.go +++ b/vendor/gopkg.in/gomail.v2/auth.go @@ -7,33 +7,51 @@ import ( "net/smtp" ) -// loginAuth is an smtp.Auth that implements the LOGIN authentication mechanism. -type loginAuth struct { +// plainAuth is an smtp.Auth that implements the PLAIN authentication mechanism. +// It fallbacks to the LOGIN mechanism if it is the only mechanism advertised +// by the server. +type plainAuth struct { username string password string host string + login bool } -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("gomail: unencrypted connection") - } - } +func (a *plainAuth) Start(server *smtp.ServerInfo) (string, []byte, error) { if server.Name != a.host { return "", nil, errors.New("gomail: wrong host name") } - return "LOGIN", nil, nil + + var plain, login bool + for _, a := range server.Auth { + switch a { + case "PLAIN": + plain = true + case "LOGIN": + login = true + } + } + + if !server.TLS && !plain && !login { + return "", nil, errors.New("gomail: unencrypted connection") + } + + if !plain && login { + a.login = true + return "LOGIN", nil, nil + } + + return "PLAIN", []byte("\x00" + a.username + "\x00" + a.password), nil } -func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) { +func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) { + if !a.login { + if more { + return nil, errors.New("gomail: unexpected server challenge") + } + return nil, nil + } + if !more { return nil, nil } diff --git a/vendor/gopkg.in/gomail.v2/auth_test.go b/vendor/gopkg.in/gomail.v2/auth_test.go index 428ef3467..20b477214 100644 --- a/vendor/gopkg.in/gomail.v2/auth_test.go +++ b/vendor/gopkg.in/gomail.v2/auth_test.go @@ -11,51 +11,103 @@ const ( testHost = "smtp.example.com" ) -type authTest struct { +var testAuth = &plainAuth{ + username: testUser, + password: testPwd, + host: testHost, +} + +type plainAuthTest struct { auths []string challenges []string tls bool + wantProto string wantData []string wantError bool } func TestNoAdvertisement(t *testing.T) { - testLoginAuth(t, &authTest{ - auths: []string{}, - tls: false, - wantError: true, + testPlainAuth(t, &plainAuthTest{ + auths: []string{}, + challenges: []string{"Username:", "Password:"}, + tls: false, + wantProto: "PLAIN", + wantError: true, }) } func TestNoAdvertisementTLS(t *testing.T) { - testLoginAuth(t, &authTest{ + testPlainAuth(t, &plainAuthTest{ auths: []string{}, challenges: []string{"Username:", "Password:"}, tls: true, - wantData: []string{"", testUser, testPwd}, + wantProto: "PLAIN", + wantData: []string{"\x00" + testUser + "\x00" + testPwd}, }) } -func TestLogin(t *testing.T) { - testLoginAuth(t, &authTest{ +func TestPlain(t *testing.T) { + testPlainAuth(t, &plainAuthTest{ + auths: []string{"PLAIN"}, + challenges: []string{"Username:", "Password:"}, + tls: false, + wantProto: "PLAIN", + wantData: []string{"\x00" + testUser + "\x00" + testPwd}, + }) +} + +func TestPlainTLS(t *testing.T) { + testPlainAuth(t, &plainAuthTest{ + auths: []string{"PLAIN"}, + challenges: []string{"Username:", "Password:"}, + tls: true, + wantProto: "PLAIN", + wantData: []string{"\x00" + testUser + "\x00" + testPwd}, + }) +} + +func TestPlainAndLogin(t *testing.T) { + testPlainAuth(t, &plainAuthTest{ auths: []string{"PLAIN", "LOGIN"}, challenges: []string{"Username:", "Password:"}, tls: false, + wantProto: "PLAIN", + wantData: []string{"\x00" + testUser + "\x00" + testPwd}, + }) +} + +func TestPlainAndLoginTLS(t *testing.T) { + testPlainAuth(t, &plainAuthTest{ + auths: []string{"PLAIN", "LOGIN"}, + challenges: []string{"Username:", "Password:"}, + tls: true, + wantProto: "PLAIN", + wantData: []string{"\x00" + testUser + "\x00" + testPwd}, + }) +} + +func TestLogin(t *testing.T) { + testPlainAuth(t, &plainAuthTest{ + auths: []string{"LOGIN"}, + challenges: []string{"Username:", "Password:"}, + tls: false, + wantProto: "LOGIN", wantData: []string{"", testUser, testPwd}, }) } func TestLoginTLS(t *testing.T) { - testLoginAuth(t, &authTest{ + testPlainAuth(t, &plainAuthTest{ auths: []string{"LOGIN"}, challenges: []string{"Username:", "Password:"}, tls: true, + wantProto: "LOGIN", wantData: []string{"", testUser, testPwd}, }) } -func testLoginAuth(t *testing.T, test *authTest) { - auth := &loginAuth{ +func testPlainAuth(t *testing.T, test *plainAuthTest) { + auth := &plainAuth{ username: testUser, password: testPwd, host: testHost, @@ -67,13 +119,13 @@ func testLoginAuth(t *testing.T, test *authTest) { } proto, toServer, err := auth.Start(server) if err != nil && !test.wantError { - t.Fatalf("loginAuth.Start(): %v", err) + t.Fatalf("plainAuth.Start(): %v", err) } if err != nil && test.wantError { return } - if proto != "LOGIN" { - t.Errorf("invalid protocol, got %q, want LOGIN", proto) + if proto != test.wantProto { + t.Errorf("invalid protocol, got %q, want %q", proto, test.wantProto) } i := 0 @@ -82,6 +134,10 @@ func testLoginAuth(t *testing.T, test *authTest) { t.Errorf("Invalid response, got %q, want %q", got, test.wantData[i]) } + if proto == "PLAIN" { + return + } + for _, challenge := range test.challenges { i++ if i >= len(test.wantData) { @@ -90,7 +146,7 @@ func testLoginAuth(t *testing.T, test *authTest) { toServer, err = auth.Next([]byte(challenge), true) if err != nil { - t.Fatalf("loginAuth.Auth(): %v", err) + t.Fatalf("plainAuth.Auth(): %v", err) } got = string(toServer) if got != test.wantData[i] { diff --git a/vendor/gopkg.in/gomail.v2/example_test.go b/vendor/gopkg.in/gomail.v2/example_test.go index 90008abe8..8d9c6c293 100644 --- a/vendor/gopkg.in/gomail.v2/example_test.go +++ b/vendor/gopkg.in/gomail.v2/example_test.go @@ -19,7 +19,7 @@ func Example() { m.SetBody("text/html", "Hello <b>Bob</b> and <i>Cora</i>!") m.Attach("/home/Alex/lolcat.jpg") - d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") + d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456") // Send the email to Bob, Cora and Dan. if err := d.DialAndSend(m); err != nil { @@ -32,7 +32,7 @@ func Example_daemon() { ch := make(chan *gomail.Message) go func() { - d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") + d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456") var s gomail.SendCloser var err error @@ -79,7 +79,7 @@ func Example_newsletter() { Address string } - d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") + d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456") s, err := d.Dial() if err != nil { panic(err) @@ -151,10 +151,6 @@ func ExampleSetHeader() { m.Attach("foo.jpg", gomail.SetHeader(h)) } -func ExampleRename() { - m.Attach("/tmp/0000146.jpg", gomail.Rename("picture.jpg")) -} - func ExampleMessage_AddAlternative() { m.SetBody("text/plain", "Hello!") m.AddAlternative("text/html", "<p>Hello!</p>") @@ -217,7 +213,3 @@ func ExampleSetCharset() { func ExampleSetEncoding() { m = gomail.NewMessage(gomail.SetEncoding(gomail.Base64)) } - -func ExampleSetPartEncoding() { - m.SetBody("text/plain", "Hello!", gomail.SetPartEncoding(gomail.Unencoded)) -} diff --git a/vendor/gopkg.in/gomail.v2/message.go b/vendor/gopkg.in/gomail.v2/message.go index 4bffb1e7f..2f75368bd 100644 --- a/vendor/gopkg.in/gomail.v2/message.go +++ b/vendor/gopkg.in/gomail.v2/message.go @@ -11,7 +11,7 @@ import ( // Message represents an email. type Message struct { header header - parts []*part + parts []part attachments []*file embedded []*file charset string @@ -23,9 +23,8 @@ type Message struct { type header map[string][]string type part struct { - contentType string - copier func(io.Writer) error - encoding Encoding + header header + copier func(io.Writer) error } // NewMessage creates a new message. It uses UTF-8 and quoted-printable encoding @@ -127,10 +126,6 @@ func (m *Message) SetAddressHeader(field, address, name string) { // FormatAddress formats an address and a name as a valid RFC 5322 address. func (m *Message) FormatAddress(address, name string) string { - if name == "" { - return address - } - enc := m.encodeString(name) if enc == name { m.buf.WriteByte('"') @@ -182,60 +177,53 @@ func (m *Message) GetHeader(field string) []string { return m.header[field] } -// SetBody sets the body of the message. It replaces any content previously set -// by SetBody, AddAlternative or AddAlternativeWriter. -func (m *Message) SetBody(contentType, body string, settings ...PartSetting) { - m.parts = []*part{m.newPart(contentType, newCopier(body), settings)} +// SetBody sets the body of the message. +func (m *Message) SetBody(contentType, body string) { + m.parts = []part{ + { + header: m.getPartHeader(contentType), + copier: func(w io.Writer) error { + _, err := io.WriteString(w, body) + return err + }, + }, + } } // AddAlternative adds an alternative part to the message. // // It is commonly used to send HTML emails that default to the plain text -// version for backward compatibility. AddAlternative appends the new part to -// the end of the message. So the plain text part should be added before the -// HTML part. See http://en.wikipedia.org/wiki/MIME#Alternative -func (m *Message) AddAlternative(contentType, body string, settings ...PartSetting) { - m.AddAlternativeWriter(contentType, newCopier(body), settings...) -} - -func newCopier(s string) func(io.Writer) error { - return func(w io.Writer) error { - _, err := io.WriteString(w, s) - return err - } +// version for backward compatibility. +// +// More info: http://en.wikipedia.org/wiki/MIME#Alternative +func (m *Message) AddAlternative(contentType, body string) { + m.parts = append(m.parts, + part{ + header: m.getPartHeader(contentType), + copier: func(w io.Writer) error { + _, err := io.WriteString(w, body) + return err + }, + }, + ) } // AddAlternativeWriter adds an alternative part to the message. It can be // useful with the text/template or html/template packages. -func (m *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error, settings ...PartSetting) { - m.parts = append(m.parts, m.newPart(contentType, f, settings)) -} - -func (m *Message) newPart(contentType string, f func(io.Writer) error, settings []PartSetting) *part { - p := &part{ - contentType: contentType, - copier: f, - encoding: m.encoding, - } - - for _, s := range settings { - s(p) +func (m *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error) { + m.parts = []part{ + { + header: m.getPartHeader(contentType), + copier: f, + }, } - - return p } -// A PartSetting can be used as an argument in Message.SetBody, -// Message.AddAlternative or Message.AddAlternativeWriter to configure the part -// added to a message. -type PartSetting func(*part) - -// SetPartEncoding sets the encoding of the part added to the message. By -// default, parts use the same encoding than the message. -func SetPartEncoding(e Encoding) PartSetting { - return PartSetting(func(p *part) { - p.encoding = e - }) +func (m *Message) getPartHeader(contentType string) header { + return map[string][]string{ + "Content-Type": {contentType + "; charset=" + m.charset}, + "Content-Transfer-Encoding": {string(m.encoding)}, + } } type file struct { @@ -264,14 +252,6 @@ func SetHeader(h map[string][]string) FileSetting { } } -// Rename is a file setting to set the name of the attachment if the name is -// different than the filename on disk. -func Rename(name string) FileSetting { - return func(f *file) { - f.Name = name - } -} - // SetCopyFunc is a file setting to replace the function that runs when the // message is sent. It should copy the content of the file to the io.Writer. // diff --git a/vendor/gopkg.in/gomail.v2/message_test.go b/vendor/gopkg.in/gomail.v2/message_test.go index acceff2a6..fdd9ff9bd 100644 --- a/vendor/gopkg.in/gomail.v2/message_test.go +++ b/vendor/gopkg.in/gomail.v2/message_test.go @@ -63,6 +63,29 @@ func TestMessage(t *testing.T) { testMessage(t, m, 0, want) } +func TestBodyWriter(t *testing.T) { + m := NewMessage() + m.SetHeader("From", "from@example.com") + m.SetHeader("To", "to@example.com") + m.AddAlternativeWriter("text/plain", func(w io.Writer) error { + _, err := w.Write([]byte("Test message")) + return err + }) + + want := &message{ + from: "from@example.com", + to: []string{"to@example.com"}, + content: "From: from@example.com\r\n" + + "To: to@example.com\r\n" + + "Content-Type: text/plain; charset=UTF-8\r\n" + + "Content-Transfer-Encoding: quoted-printable\r\n" + + "\r\n" + + "Test message", + } + + testMessage(t, m, 0, want) +} + func TestCustomMessage(t *testing.T) { m := NewMessage(SetCharset("ISO-8859-1"), SetEncoding(Base64)) m.SetHeaders(map[string][]string{ @@ -150,8 +173,7 @@ func TestAlternative(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Content-Type: multipart/alternative;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + + "Content-Type: multipart/alternative; boundary=_BOUNDARY_1_\r\n" + "\r\n" + "--_BOUNDARY_1_\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + @@ -169,74 +191,6 @@ func TestAlternative(t *testing.T) { testMessage(t, m, 1, want) } -func TestPartSetting(t *testing.T) { - m := NewMessage() - m.SetHeader("From", "from@example.com") - m.SetHeader("To", "to@example.com") - m.SetBody("text/plain; format=flowed", "¡Hola, señor!", SetPartEncoding(Unencoded)) - m.AddAlternative("text/html", "¡<b>Hola</b>, <i>señor</i>!</h1>") - - want := &message{ - from: "from@example.com", - to: []string{"to@example.com"}, - content: "From: from@example.com\r\n" + - "To: to@example.com\r\n" + - "Content-Type: multipart/alternative;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + - "\r\n" + - "--_BOUNDARY_1_\r\n" + - "Content-Type: text/plain; format=flowed; charset=UTF-8\r\n" + - "Content-Transfer-Encoding: 8bit\r\n" + - "\r\n" + - "¡Hola, señor!\r\n" + - "--_BOUNDARY_1_\r\n" + - "Content-Type: text/html; charset=UTF-8\r\n" + - "Content-Transfer-Encoding: quoted-printable\r\n" + - "\r\n" + - "=C2=A1<b>Hola</b>, <i>se=C3=B1or</i>!</h1>\r\n" + - "--_BOUNDARY_1_--\r\n", - } - - testMessage(t, m, 1, want) -} - -func TestBodyWriter(t *testing.T) { - m := NewMessage() - m.SetHeader("From", "from@example.com") - m.SetHeader("To", "to@example.com") - m.AddAlternativeWriter("text/plain", func(w io.Writer) error { - _, err := w.Write([]byte("Test message")) - return err - }) - m.AddAlternativeWriter("text/html", func(w io.Writer) error { - _, err := w.Write([]byte("Test HTML")) - return err - }) - - want := &message{ - from: "from@example.com", - to: []string{"to@example.com"}, - content: "From: from@example.com\r\n" + - "To: to@example.com\r\n" + - "Content-Type: multipart/alternative;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + - "\r\n" + - "--_BOUNDARY_1_\r\n" + - "Content-Type: text/plain; charset=UTF-8\r\n" + - "Content-Transfer-Encoding: quoted-printable\r\n" + - "\r\n" + - "Test message\r\n" + - "--_BOUNDARY_1_\r\n" + - "Content-Type: text/html; charset=UTF-8\r\n" + - "Content-Transfer-Encoding: quoted-printable\r\n" + - "\r\n" + - "Test HTML\r\n" + - "--_BOUNDARY_1_--\r\n", - } - - testMessage(t, m, 1, want) -} - func TestAttachmentOnly(t *testing.T) { m := NewMessage() m.SetHeader("From", "from@example.com") @@ -270,8 +224,7 @@ func TestAttachment(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Content-Type: multipart/mixed;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + + "Content-Type: multipart/mixed; boundary=_BOUNDARY_1_\r\n" + "\r\n" + "--_BOUNDARY_1_\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + @@ -290,40 +243,6 @@ func TestAttachment(t *testing.T) { testMessage(t, m, 1, want) } -func TestRename(t *testing.T) { - m := NewMessage() - m.SetHeader("From", "from@example.com") - m.SetHeader("To", "to@example.com") - m.SetBody("text/plain", "Test") - name, copy := mockCopyFile("/tmp/test.pdf") - rename := Rename("another.pdf") - m.Attach(name, copy, rename) - - want := &message{ - from: "from@example.com", - to: []string{"to@example.com"}, - content: "From: from@example.com\r\n" + - "To: to@example.com\r\n" + - "Content-Type: multipart/mixed;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + - "\r\n" + - "--_BOUNDARY_1_\r\n" + - "Content-Type: text/plain; charset=UTF-8\r\n" + - "Content-Transfer-Encoding: quoted-printable\r\n" + - "\r\n" + - "Test\r\n" + - "--_BOUNDARY_1_\r\n" + - "Content-Type: application/pdf; name=\"another.pdf\"\r\n" + - "Content-Disposition: attachment; filename=\"another.pdf\"\r\n" + - "Content-Transfer-Encoding: base64\r\n" + - "\r\n" + - base64.StdEncoding.EncodeToString([]byte("Content of test.pdf")) + "\r\n" + - "--_BOUNDARY_1_--\r\n", - } - - testMessage(t, m, 1, want) -} - func TestAttachmentsOnly(t *testing.T) { m := NewMessage() m.SetHeader("From", "from@example.com") @@ -336,8 +255,7 @@ func TestAttachmentsOnly(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Content-Type: multipart/mixed;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + + "Content-Type: multipart/mixed; boundary=_BOUNDARY_1_\r\n" + "\r\n" + "--_BOUNDARY_1_\r\n" + "Content-Type: application/pdf; name=\"test.pdf\"\r\n" + @@ -370,8 +288,7 @@ func TestAttachments(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Content-Type: multipart/mixed;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + + "Content-Type: multipart/mixed; boundary=_BOUNDARY_1_\r\n" + "\r\n" + "--_BOUNDARY_1_\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + @@ -409,8 +326,7 @@ func TestEmbedded(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Content-Type: multipart/related;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + + "Content-Type: multipart/related; boundary=_BOUNDARY_1_\r\n" + "\r\n" + "--_BOUNDARY_1_\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + @@ -451,16 +367,13 @@ func TestFullMessage(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Content-Type: multipart/mixed;\r\n" + - " boundary=_BOUNDARY_1_\r\n" + + "Content-Type: multipart/mixed; boundary=_BOUNDARY_1_\r\n" + "\r\n" + "--_BOUNDARY_1_\r\n" + - "Content-Type: multipart/related;\r\n" + - " boundary=_BOUNDARY_2_\r\n" + + "Content-Type: multipart/related; boundary=_BOUNDARY_2_\r\n" + "\r\n" + "--_BOUNDARY_2_\r\n" + - "Content-Type: multipart/alternative;\r\n" + - " boundary=_BOUNDARY_3_\r\n" + + "Content-Type: multipart/alternative; boundary=_BOUNDARY_3_\r\n" + "\r\n" + "--_BOUNDARY_3_\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + @@ -564,34 +477,6 @@ func TestBase64LineLength(t *testing.T) { testMessage(t, m, 0, want) } -func TestEmptyName(t *testing.T) { - m := NewMessage() - m.SetAddressHeader("From", "from@example.com", "") - - want := &message{ - from: "from@example.com", - content: "From: from@example.com\r\n", - } - - testMessage(t, m, 0, want) -} - -func TestEmptyHeader(t *testing.T) { - m := NewMessage() - m.SetHeaders(map[string][]string{ - "From": {"from@example.com"}, - "X-Empty": nil, - }) - - want := &message{ - from: "from@example.com", - content: "From: from@example.com\r\n" + - "X-Empty:\r\n", - } - - testMessage(t, m, 0, want) -} - func testMessage(t *testing.T, m *Message, bCount int, want *message) { err := Send(stubSendMail(t, bCount, want), m) if err != nil { diff --git a/vendor/gopkg.in/gomail.v2/mime.go b/vendor/gopkg.in/gomail.v2/mime.go index 194d4a769..51cba724b 100644 --- a/vendor/gopkg.in/gomail.v2/mime.go +++ b/vendor/gopkg.in/gomail.v2/mime.go @@ -5,7 +5,6 @@ package gomail import ( "mime" "mime/quotedprintable" - "strings" ) var newQPWriter = quotedprintable.NewWriter @@ -15,7 +14,6 @@ type mimeEncoder struct { } var ( - bEncoding = mimeEncoder{mime.BEncoding} - qEncoding = mimeEncoder{mime.QEncoding} - lastIndexByte = strings.LastIndexByte + bEncoding = mimeEncoder{mime.BEncoding} + qEncoding = mimeEncoder{mime.QEncoding} ) diff --git a/vendor/gopkg.in/gomail.v2/mime_go14.go b/vendor/gopkg.in/gomail.v2/mime_go14.go index 3dc26aa2a..246e2e5e5 100644 --- a/vendor/gopkg.in/gomail.v2/mime_go14.go +++ b/vendor/gopkg.in/gomail.v2/mime_go14.go @@ -11,15 +11,6 @@ type mimeEncoder struct { } var ( - bEncoding = mimeEncoder{quotedprintable.BEncoding} - qEncoding = mimeEncoder{quotedprintable.QEncoding} - lastIndexByte = func(s string, c byte) int { - for i := len(s) - 1; i >= 0; i-- { - - if s[i] == c { - return i - } - } - return -1 - } + bEncoding = mimeEncoder{quotedprintable.BEncoding} + qEncoding = mimeEncoder{quotedprintable.QEncoding} ) diff --git a/vendor/gopkg.in/gomail.v2/send.go b/vendor/gopkg.in/gomail.v2/send.go index 9115ebe72..3e6726509 100644 --- a/vendor/gopkg.in/gomail.v2/send.go +++ b/vendor/gopkg.in/gomail.v2/send.go @@ -20,7 +20,7 @@ type SendCloser interface { Close() error } -// A SendFunc is a function that sends emails to the given addresses. +// A SendFunc is a function that sends emails to the given adresses. // // The SendFunc type is an adapter to allow the use of ordinary functions as // email senders. If f is a function with the appropriate signature, SendFunc(f) @@ -108,9 +108,10 @@ func addAddress(list []string, addr string) []string { } func parseAddress(field string) (string, error) { - addr, err := mail.ParseAddress(field) - if err != nil { - return "", fmt.Errorf("gomail: invalid address %q: %v", field, err) + a, err := mail.ParseAddress(field) + if a == nil { + return "", err } - return addr.Address, nil + + return a.Address, err } diff --git a/vendor/gopkg.in/gomail.v2/smtp.go b/vendor/gopkg.in/gomail.v2/smtp.go index 2aa49c8b6..cf773a102 100644 --- a/vendor/gopkg.in/gomail.v2/smtp.go +++ b/vendor/gopkg.in/gomail.v2/smtp.go @@ -6,8 +6,6 @@ import ( "io" "net" "net/smtp" - "strings" - "time" ) // A Dialer is a dialer to an SMTP server. @@ -16,10 +14,6 @@ type Dialer struct { Host string // Port represents the port of the SMTP server. Port int - // Username is the username to use to authenticate to the SMTP server. - Username string - // Password is the password to use to authenticate to the SMTP server. - Password string // Auth represents the authentication mechanism used to authenticate to the // SMTP server. Auth smtp.Auth @@ -30,94 +24,83 @@ type Dialer struct { // TSLConfig represents the TLS configuration used for the TLS (when the // STARTTLS extension is used) or SSL connection. TLSConfig *tls.Config - // LocalName is the hostname sent to the SMTP server with the HELO command. - // By default, "localhost" is sent. - LocalName string } -// NewDialer returns a new SMTP Dialer. The given parameters are used to connect -// to the SMTP server. -func NewDialer(host string, port int, username, password string) *Dialer { - return &Dialer{ - Host: host, - Port: port, - Username: username, - Password: password, - SSL: port == 465, - } -} - -// NewPlainDialer returns a new SMTP Dialer. The given parameters are used to -// connect to the SMTP server. +// NewPlainDialer returns a Dialer. The given parameters are used to connect to +// the SMTP server via a PLAIN authentication mechanism. // -// Deprecated: Use NewDialer instead. +// It fallbacks to the LOGIN mechanism if it is the only mechanism advertised by +// the server. func NewPlainDialer(host string, port int, username, password string) *Dialer { - return NewDialer(host, port, username, password) + return &Dialer{ + Host: host, + Port: port, + Auth: &plainAuth{ + username: username, + password: password, + host: host, + }, + SSL: port == 465, + } } // Dial dials and authenticates to an SMTP server. The returned SendCloser // should be closed when done using it. func (d *Dialer) Dial() (SendCloser, error) { - conn, err := netDialTimeout("tcp", addr(d.Host, d.Port), 10*time.Second) + c, err := d.dial() if err != nil { return nil, err } + if d.Auth != nil { + if ok, _ := c.Extension("AUTH"); ok { + if err = c.Auth(d.Auth); err != nil { + c.Close() + return nil, err + } + } + } + + return &smtpSender{c}, nil +} + +func (d *Dialer) dial() (smtpClient, error) { if d.SSL { - conn = tlsClient(conn, d.tlsConfig()) + return d.sslDial() } + return d.starttlsDial() +} - c, err := smtpNewClient(conn, d.Host) +func (d *Dialer) starttlsDial() (smtpClient, error) { + c, err := smtpDial(addr(d.Host, d.Port)) if err != nil { return nil, err } - if d.LocalName != "" { - if err := c.Hello(d.LocalName); err != nil { + if ok, _ := c.Extension("STARTTLS"); ok { + if err := c.StartTLS(d.tlsConfig()); err != nil { + c.Close() return nil, err } } - if !d.SSL { - if ok, _ := c.Extension("STARTTLS"); ok { - if err := c.StartTLS(d.tlsConfig()); err != nil { - c.Close() - return nil, err - } - } - } - - if d.Auth == nil && d.Username != "" { - if ok, auths := c.Extension("AUTH"); ok { - if strings.Contains(auths, "CRAM-MD5") { - d.Auth = smtp.CRAMMD5Auth(d.Username, d.Password) - } else if strings.Contains(auths, "LOGIN") && - !strings.Contains(auths, "PLAIN") { - d.Auth = &loginAuth{ - username: d.Username, - password: d.Password, - host: d.Host, - } - } else { - d.Auth = smtp.PlainAuth("", d.Username, d.Password, d.Host) - } - } - } + return c, nil +} - if d.Auth != nil { - if err = c.Auth(d.Auth); err != nil { - c.Close() - return nil, err - } +func (d *Dialer) sslDial() (smtpClient, error) { + conn, err := tlsDial("tcp", addr(d.Host, d.Port), d.tlsConfig()) + if err != nil { + return nil, err } - return &smtpSender{c, d}, nil + return newClient(conn, d.Host) } func (d *Dialer) tlsConfig() *tls.Config { if d.TLSConfig == nil { return &tls.Config{ServerName: d.Host} } + return d.TLSConfig } @@ -139,21 +122,10 @@ func (d *Dialer) DialAndSend(m ...*Message) error { type smtpSender struct { smtpClient - d *Dialer } func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error { if err := c.Mail(from); err != nil { - if err == io.EOF { - // This is probably due to a timeout, so reconnect and try again. - sc, derr := c.d.Dial() - if derr == nil { - if s, ok := sc.(*smtpSender); ok { - *c = *s - return c.Send(from, to, msg) - } - } - } return err } @@ -182,15 +154,16 @@ func (c *smtpSender) Close() error { // Stubbed out for tests. var ( - netDialTimeout = net.DialTimeout - tlsClient = tls.Client - smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) { + smtpDial = func(addr string) (smtpClient, error) { + return smtp.Dial(addr) + } + tlsDial = tls.Dial + newClient = func(conn net.Conn, host string) (smtpClient, error) { return smtp.NewClient(conn, host) } ) type smtpClient interface { - Hello(string) error Extension(string) (bool, string) StartTLS(*tls.Config) error Auth(smtp.Auth) error diff --git a/vendor/gopkg.in/gomail.v2/smtp_test.go b/vendor/gopkg.in/gomail.v2/smtp_test.go index b6f91555b..c8503489b 100644 --- a/vendor/gopkg.in/gomail.v2/smtp_test.go +++ b/vendor/gopkg.in/gomail.v2/smtp_test.go @@ -8,7 +8,6 @@ import ( "net/smtp" "reflect" "testing" - "time" ) const ( @@ -17,14 +16,12 @@ const ( ) var ( - testConn = &net.TCPConn{} testTLSConn = &tls.Conn{} testConfig = &tls.Config{InsecureSkipVerify: true} - testAuth = smtp.PlainAuth("", testUser, testPwd, testHost) ) func TestDialer(t *testing.T) { - d := NewDialer(testHost, testPort, "user", "pwd") + d := NewPlainDialer(testHost, testPort, "user", "pwd") testSendMail(t, d, []string{ "Extension STARTTLS", "StartTLS", @@ -42,7 +39,7 @@ func TestDialer(t *testing.T) { } func TestDialerSSL(t *testing.T) { - d := NewDialer(testHost, testSSLPort, "user", "pwd") + d := NewPlainDialer(testHost, testSSLPort, "user", "pwd") testSendMail(t, d, []string{ "Extension AUTH", "Auth", @@ -58,11 +55,9 @@ func TestDialerSSL(t *testing.T) { } func TestDialerConfig(t *testing.T) { - d := NewDialer(testHost, testPort, "user", "pwd") - d.LocalName = "test" + d := NewPlainDialer(testHost, testPort, "user", "pwd") d.TLSConfig = testConfig testSendMail(t, d, []string{ - "Hello test", "Extension STARTTLS", "StartTLS", "Extension AUTH", @@ -79,11 +74,9 @@ func TestDialerConfig(t *testing.T) { } func TestDialerSSLConfig(t *testing.T) { - d := NewDialer(testHost, testSSLPort, "user", "pwd") - d.LocalName = "test" + d := NewPlainDialer(testHost, testSSLPort, "user", "pwd") d.TLSConfig = testConfig testSendMail(t, d, []string{ - "Hello test", "Extension AUTH", "Auth", "Mail " + testFrom, @@ -116,40 +109,13 @@ func TestDialerNoAuth(t *testing.T) { }) } -func TestDialerTimeout(t *testing.T) { - d := &Dialer{ - Host: testHost, - Port: testPort, - } - testSendMailTimeout(t, d, []string{ - "Extension STARTTLS", - "StartTLS", - "Mail " + testFrom, - "Extension STARTTLS", - "StartTLS", - "Mail " + testFrom, - "Rcpt " + testTo1, - "Rcpt " + testTo2, - "Data", - "Write message", - "Close writer", - "Quit", - "Close", - }) -} - type mockClient struct { - t *testing.T - i int - want []string - addr string - config *tls.Config - timeout bool -} - -func (c *mockClient) Hello(localName string) error { - c.do("Hello " + localName) - return nil + t *testing.T + i int + want []string + addr string + auth smtp.Auth + config *tls.Config } func (c *mockClient) Extension(ext string) (bool, string) { @@ -164,19 +130,13 @@ func (c *mockClient) StartTLS(config *tls.Config) error { } func (c *mockClient) Auth(a smtp.Auth) error { - if !reflect.DeepEqual(a, testAuth) { - c.t.Errorf("Invalid auth, got %#v, want %#v", a, testAuth) - } + assertAuth(c.t, a, c.auth) c.do("Auth") return nil } func (c *mockClient) Mail(from string) error { c.do("Mail " + from) - if c.timeout { - c.timeout = false - return io.EOF - } return nil } @@ -232,42 +192,32 @@ func (w *mockWriter) Close() error { } func testSendMail(t *testing.T, d *Dialer, want []string) { - doTestSendMail(t, d, want, false) -} - -func testSendMailTimeout(t *testing.T, d *Dialer, want []string) { - doTestSendMail(t, d, want, true) -} - -func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) { testClient := &mockClient{ - t: t, - want: want, - addr: addr(d.Host, d.Port), - config: d.TLSConfig, - timeout: timeout, + t: t, + want: want, + addr: addr(d.Host, d.Port), + auth: testAuth, + config: d.TLSConfig, } - netDialTimeout = func(network, address string, d time.Duration) (net.Conn, error) { - if network != "tcp" { - t.Errorf("Invalid network, got %q, want tcp", network) - } - if address != testClient.addr { - t.Errorf("Invalid address, got %q, want %q", - address, testClient.addr) - } - return testConn, nil + smtpDial = func(addr string) (smtpClient, error) { + assertAddr(t, addr, testClient.addr) + return testClient, nil } - tlsClient = func(conn net.Conn, config *tls.Config) *tls.Conn { - if conn != testConn { - t.Errorf("Invalid conn, got %#v, want %#v", conn, testConn) + tlsDial = func(network, addr string, config *tls.Config) (*tls.Conn, error) { + if network != "tcp" { + t.Errorf("Invalid network, got %q, want tcp", network) } + assertAddr(t, addr, testClient.addr) assertConfig(t, config, testClient.config) - return testTLSConn + return testTLSConn, nil } - smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) { + newClient = func(conn net.Conn, host string) (smtpClient, error) { + if conn != testTLSConn { + t.Error("Invalid TLS connection used") + } if host != testHost { t.Errorf("Invalid host, got %q, want %q", host, testHost) } @@ -279,6 +229,18 @@ func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) { } } +func assertAuth(t *testing.T, got, want smtp.Auth) { + if !reflect.DeepEqual(got, want) { + t.Errorf("Invalid auth, got %#v, want %#v", got, want) + } +} + +func assertAddr(t *testing.T, got, want string) { + if got != want { + t.Errorf("Invalid addr, got %q, want %q", got, want) + } +} + func assertConfig(t *testing.T, got, want *tls.Config) { if want == nil { want = &tls.Config{ServerName: testHost} diff --git a/vendor/gopkg.in/gomail.v2/writeto.go b/vendor/gopkg.in/gomail.v2/writeto.go index 9fb6b86e8..57a1dd7f1 100644 --- a/vendor/gopkg.in/gomail.v2/writeto.go +++ b/vendor/gopkg.in/gomail.v2/writeto.go @@ -7,7 +7,6 @@ import ( "mime" "mime/multipart" "path/filepath" - "strings" "time" ) @@ -39,7 +38,8 @@ func (w *messageWriter) writeMessage(m *Message) { w.openMultipart("alternative") } for _, part := range m.parts { - w.writePart(part, m.charset) + w.writeHeaders(part.header) + w.writeBody(part.copier, m.encoding) } if m.hasAlternativePart() { w.closeMultipart() @@ -79,7 +79,7 @@ type messageWriter struct { func (w *messageWriter) openMultipart(mimeType string) { mw := multipart.NewWriter(w) - contentType := "multipart/" + mimeType + ";\r\n boundary=" + mw.Boundary() + contentType := "multipart/" + mimeType + "; boundary=" + mw.Boundary() w.writers[w.depth] = mw if w.depth == 0 { @@ -104,14 +104,6 @@ func (w *messageWriter) closeMultipart() { } } -func (w *messageWriter) writePart(p *part, charset string) { - w.writeHeaders(map[string][]string{ - "Content-Type": {p.contentType + "; charset=" + charset}, - "Content-Transfer-Encoding": {string(p.encoding)}, - }) - w.writeBody(p.copier, p.encoding) -} - func (w *messageWriter) addFiles(files []*file, isAttachment bool) { for _, f := range files { if _, ok := f.Header["Content-Type"]; !ok { @@ -162,80 +154,24 @@ func (w *messageWriter) writeString(s string) { w.n += int64(n) } -func (w *messageWriter) writeHeader(k string, v ...string) { - w.writeString(k) - if len(v) == 0 { - w.writeString(":\r\n") - return - } - w.writeString(": ") - - // Max header line length is 78 characters in RFC 5322 and 76 characters - // in RFC 2047. So for the sake of simplicity we use the 76 characters - // limit. - charsLeft := 76 - len(k) - len(": ") - - for i, s := range v { - // If the line is already too long, insert a newline right away. - if charsLeft < 1 { - if i == 0 { - w.writeString("\r\n ") - } else { - w.writeString(",\r\n ") - } - charsLeft = 75 - } else if i != 0 { - w.writeString(", ") - charsLeft -= 2 - } - - // While the header content is too long, fold it by inserting a newline. - for len(s) > charsLeft { - s = w.writeLine(s, charsLeft) - charsLeft = 75 +func (w *messageWriter) writeStrings(a []string, sep string) { + if len(a) > 0 { + w.writeString(a[0]) + if len(a) == 1 { + return } + } + for _, s := range a[1:] { + w.writeString(sep) w.writeString(s) - if i := lastIndexByte(s, '\n'); i != -1 { - charsLeft = 75 - (len(s) - i - 1) - } else { - charsLeft -= len(s) - } } - w.writeString("\r\n") } -func (w *messageWriter) writeLine(s string, charsLeft int) string { - // If there is already a newline before the limit. Write the line. - if i := strings.IndexByte(s, '\n'); i != -1 && i < charsLeft { - w.writeString(s[:i+1]) - return s[i+1:] - } - - for i := charsLeft - 1; i >= 0; i-- { - if s[i] == ' ' { - w.writeString(s[:i]) - w.writeString("\r\n ") - return s[i+1:] - } - } - - // We could not insert a newline cleanly so look for a space or a newline - // even if it is after the limit. - for i := 75; i < len(s); i++ { - if s[i] == ' ' { - w.writeString(s[:i]) - w.writeString("\r\n ") - return s[i+1:] - } - if s[i] == '\n' { - w.writeString(s[:i+1]) - return s[i+1:] - } - } - - // Too bad, no space or newline in the whole string. Just write everything. - w.writeString(s) - return "" +func (w *messageWriter) writeHeader(k string, v ...string) { + w.writeString(k) + w.writeString(": ") + w.writeStrings(v, ", ") + w.writeString("\r\n") } func (w *messageWriter) writeHeaders(h map[string][]string) { |