summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/gomail.v2
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/gomail.v2')
-rw-r--r--vendor/gopkg.in/gomail.v2/.travis.yml1
-rw-r--r--vendor/gopkg.in/gomail.v2/README.md43
-rw-r--r--vendor/gopkg.in/gomail.v2/auth.go52
-rw-r--r--vendor/gopkg.in/gomail.v2/auth_test.go88
-rw-r--r--vendor/gopkg.in/gomail.v2/example_test.go14
-rw-r--r--vendor/gopkg.in/gomail.v2/message.go96
-rw-r--r--vendor/gopkg.in/gomail.v2/message_test.go177
-rw-r--r--vendor/gopkg.in/gomail.v2/mime.go6
-rw-r--r--vendor/gopkg.in/gomail.v2/mime_go14.go13
-rw-r--r--vendor/gopkg.in/gomail.v2/send.go11
-rw-r--r--vendor/gopkg.in/gomail.v2/smtp.go125
-rw-r--r--vendor/gopkg.in/gomail.v2/smtp_test.go118
-rw-r--r--vendor/gopkg.in/gomail.v2/writeto.go96
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) {