From ec61a8ae4f287b8d212c9ed78685f9930eaabe2f Mon Sep 17 00:00:00 2001 From: Rienzi Date: Wed, 30 Aug 2017 18:50:03 -0400 Subject: [PATCH 01/14] Added Check For Existing Files And Attachments --- send.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/send.go b/send.go index 9115ebe..b0cd0a4 100644 --- a/send.go +++ b/send.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/mail" + "os" ) // Sender is the interface that wraps the Send method. @@ -54,6 +55,10 @@ func send(s Sender, m *Message) error { return err } + if err := m.checkEmbedsAndAttachments(); err != nil { + return err + } + if err := s.Send(from, to, m); err != nil { return err } @@ -97,6 +102,20 @@ func (m *Message) getRecipients() ([]string, error) { return list, nil } +func (m *Message) checkEmbedsAndAttachments() error { + for _, file := range m.embedded { + if _, err := os.Stat(file.Name); err != nil { + return err + } + } + for _, file := range m.attachments { + if _, err := os.Stat(file.Name); err != nil { + return err + } + } + return nil +} + func addAddress(list []string, addr string) []string { for _, a := range list { if addr == a { From c331832adaea1ed9543417b573ed99c83211fde0 Mon Sep 17 00:00:00 2001 From: Rienzi Date: Wed, 30 Aug 2017 19:29:17 -0400 Subject: [PATCH 02/14] Updated Tests To Actually Create File --- message_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/message_test.go b/message_test.go index acceff2..210b2d4 100644 --- a/message_test.go +++ b/message_test.go @@ -1,6 +1,7 @@ package gomail import ( + "os" "bytes" "encoding/base64" "io" @@ -297,6 +298,9 @@ func TestRename(t *testing.T) { m.SetBody("text/plain", "Test") name, copy := mockCopyFile("/tmp/test.pdf") rename := Rename("another.pdf") + os.Create("another.pdf") + + m.Attach(name, copy, rename) want := &message{ @@ -705,6 +709,7 @@ func getBoundaries(t *testing.T, count int, m string) []string { var boundaryRegExp = regexp.MustCompile("boundary=(\\w+)") func mockCopyFile(name string) (string, FileSetting) { + os.Create(filepath.Base(name)) return name, SetCopyFunc(func(w io.Writer) error { _, err := w.Write([]byte("Content of " + filepath.Base(name))) return err From 71893bb665124aedd7282464cea0f6ad7554b0ca Mon Sep 17 00:00:00 2001 From: Rienzi Date: Fri, 8 Dec 2017 23:47:29 -0500 Subject: [PATCH 03/14] Added teardown method for files --- message_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/message_test.go b/message_test.go index 210b2d4..de0aeed 100644 --- a/message_test.go +++ b/message_test.go @@ -257,6 +257,9 @@ func TestAttachmentOnly(t *testing.T) { } testMessage(t, m, 0, want) + if err := teardownFile("/tmp/test.pdf"); err != nil { + panic(err) + } } func TestAttachment(t *testing.T) { @@ -289,6 +292,9 @@ func TestAttachment(t *testing.T) { } testMessage(t, m, 1, want) + if err := teardownFile("/tmp/test.pdf"); err != nil { + panic(err) + } } func TestRename(t *testing.T) { @@ -326,6 +332,9 @@ func TestRename(t *testing.T) { } testMessage(t, m, 1, want) + if err := teardownFile("/tmp/test.pdf"); err != nil { + panic(err) + } } func TestAttachmentsOnly(t *testing.T) { @@ -359,6 +368,12 @@ func TestAttachmentsOnly(t *testing.T) { } testMessage(t, m, 1, want) + if err := teardownFile("/tmp/test.pdf"); err != nil { + panic(err) + } + if err := teardownFile("/tmp/test.zip"); err != nil { + panic(err) + } } func TestAttachments(t *testing.T) { @@ -398,6 +413,12 @@ func TestAttachments(t *testing.T) { } testMessage(t, m, 1, want) + if err := teardownFile("/tmp/test.pdf"); err != nil { + panic(err) + } + if err := teardownFile("/tmp/test.zip"); err != nil { + panic(err) + } } func TestEmbedded(t *testing.T) { @@ -439,6 +460,12 @@ func TestEmbedded(t *testing.T) { } testMessage(t, m, 1, want) + if err := teardownFile("image1.jpg"); err != nil { + panic(err) + } + if err := teardownFile("image2.jpg"); err != nil { + panic(err) + } } func TestFullMessage(t *testing.T) { @@ -498,6 +525,14 @@ func TestFullMessage(t *testing.T) { testMessage(t, m, 3, want) + if err := teardownFile("test.pdf"); err != nil { + panic(err) + } + if err := teardownFile("image.jpg"); err != nil { + panic(err) + } + + want = &message{ from: "from@example.com", to: []string{"to@example.com"}, @@ -721,6 +756,10 @@ func mockCopyFileWithHeader(m *Message, name string, h map[string][]string) (str return name, f, SetHeader(h) } +func teardownFile(name string) err { + return os.Remove(filepath.Base(name)) +} + func BenchmarkFull(b *testing.B) { discardFunc := SendFunc(func(from string, to []string, m io.WriterTo) error { _, err := m.WriteTo(ioutil.Discard) @@ -746,5 +785,11 @@ func BenchmarkFull(b *testing.B) { panic(err) } m.Reset() + if err := teardownFile("benchmark.txt"); err != nil { + panic(err) + } + if err := teardownFile("benchmark.jpg"); err != nil { + panic(err) + } } } From cd0ee1215429d1c4444797de8a2607b2b29a581b Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 20:48:19 -0500 Subject: [PATCH 04/14] Removed Rename File Creation --- message_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/message_test.go b/message_test.go index de0aeed..467a136 100644 --- a/message_test.go +++ b/message_test.go @@ -304,7 +304,6 @@ func TestRename(t *testing.T) { m.SetBody("text/plain", "Test") name, copy := mockCopyFile("/tmp/test.pdf") rename := Rename("another.pdf") - os.Create("another.pdf") m.Attach(name, copy, rename) From 8a0aa6287002b48da8fdfb53ee4a8f1bb48a021b Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 20:52:30 -0500 Subject: [PATCH 05/14] Fixed Build Typo --- message_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_test.go b/message_test.go index 467a136..ea3d7f5 100644 --- a/message_test.go +++ b/message_test.go @@ -755,7 +755,7 @@ func mockCopyFileWithHeader(m *Message, name string, h map[string][]string) (str return name, f, SetHeader(h) } -func teardownFile(name string) err { +func teardownFile(name string) error { return os.Remove(filepath.Base(name)) } From 8ca38acf0e469692f140cbae73fea07341ae1139 Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:11:41 -0500 Subject: [PATCH 06/14] Added originalName property for file --- message.go | 2 ++ send.go | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/message.go b/message.go index 4bffb1e..725125a 100644 --- a/message.go +++ b/message.go @@ -240,6 +240,7 @@ func SetPartEncoding(e Encoding) PartSetting { type file struct { Name string + originalName string Header map[string][]string CopyFunc func(w io.Writer) error } @@ -285,6 +286,7 @@ func SetCopyFunc(f func(io.Writer) error) FileSetting { func (m *Message) appendFile(list []*file, name string, settings []FileSetting) []*file { f := &file{ + originalName: name, Name: filepath.Base(name), Header: make(map[string][]string), CopyFunc: func(w io.Writer) error { diff --git a/send.go b/send.go index b0cd0a4..99a6dd8 100644 --- a/send.go +++ b/send.go @@ -104,12 +104,12 @@ func (m *Message) getRecipients() ([]string, error) { func (m *Message) checkEmbedsAndAttachments() error { for _, file := range m.embedded { - if _, err := os.Stat(file.Name); err != nil { + if _, err := os.Stat(file.originalName); err != nil { return err } } for _, file := range m.attachments { - if _, err := os.Stat(file.Name); err != nil { + if _, err := os.Stat(file.originalName); err != nil { return err } } From c491950f38546874b49e4bf139ad1538672e355f Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:14:52 -0500 Subject: [PATCH 07/14] Fixed Typo with originalName --- message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message.go b/message.go index 725125a..7733e5e 100644 --- a/message.go +++ b/message.go @@ -286,7 +286,7 @@ func SetCopyFunc(f func(io.Writer) error) FileSetting { func (m *Message) appendFile(list []*file, name string, settings []FileSetting) []*file { f := &file{ - originalName: name, + originalName: filepath.Base(name), Name: filepath.Base(name), Header: make(map[string][]string), CopyFunc: func(w io.Writer) error { From 09b474da1c02d79df78a354b884acaef1662d89f Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:21:04 -0500 Subject: [PATCH 08/14] Added Tests for Embed/Attachment Validation --- send_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/send_test.go b/send_test.go index ba59cd3..f8d12aa 100644 --- a/send_test.go +++ b/send_test.go @@ -50,6 +50,47 @@ func TestSend(t *testing.T) { } } +func TestSendValidatesEmbeds(t *testing.T) { + s := &mockSendCloser{ + mockSender: stubSend(t, testFrom, []string{testTo1, testTo2}, testMsg), + close: func() error { + t.Error("Close() should not be called in Send()") + return nil + }, + } + + m := getTestMessage() + m.Embed("this-file-does-not-exist") + + err := Send(s, m) + if err == nil || !strings.HasSuffix(err.Error(), + "no such file or directory") { + t.Errorf("Send(): expected stat error but got %v", err) + } +} + + +func TestSendValidatesAttachments(t *testing.T) { + s := &mockSendCloser{ + mockSender: stubSend(t, testFrom, []string{testTo1, testTo2}, testMsg), + close: func() error { + t.Error("Close() should not be called in Send()") + return nil + }, + } + + m := getTestMessage() + m.Attach("this-file-does-not-exist") + + err := Send(s, m) + if err == nil || !strings.HasSuffix(err.Error(), + "no such file or directory") { + t.Errorf("Send(): expected stat error but got %v", err) + } +} + + + func getTestMessage() *Message { m := NewMessage() m.SetHeader("From", testFrom) From c117660e17a3bf344286d2806111ba0f80bc237e Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:23:24 -0500 Subject: [PATCH 09/14] Fogot to add strings import --- send_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/send_test.go b/send_test.go index f8d12aa..a5b426f 100644 --- a/send_test.go +++ b/send_test.go @@ -5,6 +5,7 @@ import ( "io" "reflect" "testing" + "strings" ) const ( From f5e292ee7b7f1c063995d3ca23f2e5b7d2d921bc Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:48:13 -0500 Subject: [PATCH 10/14] Removed first net/mail import --- send.go | 1 - 1 file changed, 1 deletion(-) diff --git a/send.go b/send.go index e14295d..241982c 100644 --- a/send.go +++ b/send.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "io" - "net/mail" "os" stdmail "net/mail" ) From 4a60beb645762fe11b64d54ef245eb4417c4d9fb Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:52:27 -0500 Subject: [PATCH 11/14] Revert "Fogot to add strings import" This reverts commit c117660e17a3bf344286d2806111ba0f80bc237e. --- send_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/send_test.go b/send_test.go index 0e8496c..53ca7ec 100644 --- a/send_test.go +++ b/send_test.go @@ -5,7 +5,6 @@ import ( "io" "reflect" "testing" - "strings" ) const ( From aaa67cd09604263226cdfd244dac64fd11768134 Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:57:29 -0500 Subject: [PATCH 12/14] Revert A bunch of things This reverts commit 4a60beb645762fe11b64d54ef245eb4417c4d9fb. --- send_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/send_test.go b/send_test.go index 53ca7ec..0e8496c 100644 --- a/send_test.go +++ b/send_test.go @@ -5,6 +5,7 @@ import ( "io" "reflect" "testing" + "strings" ) const ( From bafcd8493c9587bca5871c2935699032a88d1e16 Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:57:59 -0500 Subject: [PATCH 13/14] Revert "Removed first net/mail import" This reverts commit f5e292ee7b7f1c063995d3ca23f2e5b7d2d921bc. --- send.go | 1 + 1 file changed, 1 insertion(+) diff --git a/send.go b/send.go index 241982c..e14295d 100644 --- a/send.go +++ b/send.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "net/mail" "os" stdmail "net/mail" ) From 3e277d0e96f13b2a24cd564aa62412f069f3457e Mon Sep 17 00:00:00 2001 From: Rienzi Date: Sat, 9 Dec 2017 21:59:34 -0500 Subject: [PATCH 14/14] Revert "Merge branch 'v2' into Fixing-Attachment-Error" This reverts commit c273b3f2ebc55da7c8048695697d6501d081ca25, reversing changes made to c117660e17a3bf344286d2806111ba0f80bc237e. --- .gitignore | 17 -------------- .travis.yml | 12 ---------- CHANGELOG.md | 3 --- README.md | 60 +++++++++++++++---------------------------------- auth.go | 2 +- auth_test.go | 2 +- doc.go | 5 ++--- example_test.go | 46 ++++++++++++++++++------------------- message.go | 2 +- message_test.go | 2 +- mime.go | 2 +- mime_go14.go | 2 +- send.go | 5 ++--- send_test.go | 2 +- smtp.go | 60 +++++++++++-------------------------------------- smtp_test.go | 44 +++++++++--------------------------- writeto.go | 2 +- 17 files changed, 77 insertions(+), 191 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index cc4721c..0000000 --- a/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ - - -# Binaries for programs and plugins -*.exe -*.dll -*.so -*.dylib - -# Test binary, build with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - - -# IDE's -.idea/ diff --git a/.travis.yml b/.travis.yml index cba5708..48915e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,4 @@ go: - 1.4 - 1.5 - 1.6 - - 1.7 - - 1.8 - - 1.9 - tip - -# safelist -branches: - only: - - master - - v2 - -notifications: - email: false diff --git a/CHANGELOG.md b/CHANGELOG.md index be37fba..a797ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,6 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## 2017-12-06 Original project forked -https://github.com/go-gomail/gomail/issues/104 - ## [2.0.0] - 2015-09-02 - Mailer has been removed. It has been replaced by Dialer and Sender. diff --git a/README.md b/README.md index 11eb6a8..b3be9e1 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,5 @@ # Gomail -[![Build Status](https://travis-ci.org/go-mail/mail.svg?branch=master)](https://travis-ci.org/go-mail/mail) [![Code Coverage](http://gocover.io/_badge/github.com/go-mail/mail)](http://gocover.io/github.com/go-mail/mail) [![Documentation](https://godoc.org/github.com/go-mail/mail?status.svg)](https://godoc.org/github.com/go-mail/mail) - -This is an actively maintained fork of [Gomail][1] and includes fixes and -improvements for a number of outstanding issues. The current progress is -as follows: - - - [x] Timeouts and retries can be specified outside of the 10 second default. - - [x] Proxying is supported through specifying a custom [NetDialTimeout][2]. - - [ ] Filenames are properly encoded for non-ASCII characters. - - [ ] Email addresses are properly encoded for non-ASCII characters. - - [ ] Embedded files and attachments are tested for their existence. - - [ ] An `io.Reader` can be supplied when embedding and attaching files. - -See [Transitioning Existing Codebases][3] for more information on switching. - -[1]: https://github.com/go-gomail/gomail -[2]: https://godoc.org/gopkg.in/mail.v2#NetDialTimeout -[3]: #transitioning-existing-codebases +[![Build Status](https://travis-ci.org/go-gomail/gomail.svg?branch=v2)](https://travis-ci.org/go-gomail/gomail) [![Code Coverage](http://gocover.io/_badge/gopkg.in/gomail.v2)](http://gocover.io/gopkg.in/gomail.v2) [![Documentation](https://godoc.org/gopkg.in/gomail.v2?status.svg)](https://godoc.org/gopkg.in/gomail.v2) ## Introduction @@ -27,6 +10,9 @@ 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. + It requires Go 1.2 or newer. With Go 1.5, no external dependencies are used. @@ -43,17 +29,17 @@ Gomail supports: ## Documentation -https://godoc.org/github.com/go-mail/mail +https://godoc.org/gopkg.in/gomail.v2 ## Download - go get gopkg.in/mail.v2 + go get gopkg.in/gomail.v2 ## Examples -See the [examples in the documentation](https://godoc.org/github.com/go-mail/mail#example-package). +See the [examples in the documentation](https://godoc.org/gopkg.in/gomail.v2#example-package). ## FAQ @@ -65,33 +51,23 @@ 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`: -```go -package main + package main -import ( - "crypto/tls" + import ( + "crypto/tls" - "gopkg.in/mail.v2" -) + "gopkg.in/gomail.v2" + ) -func main() { - d := mail.NewDialer("smtp.example.com", 587, "user", "123456") - d.TLSConfig = &tls.Config{InsecureSkipVerify: true} + func main() { + d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") + d.TLSConfig = &tls.Config{InsecureSkipVerify: true} - // Send emails using d. -} -``` + // Send emails using d. + } Note, however, that this is insecure and should not be used in production. -### Transitioning Existing Codebases - -If you're already using the original Gomail, switching is as easy as updating -the import line to: - -``` -import gomail "gopkg.in/mail.v2" -``` ## Contribute @@ -109,7 +85,7 @@ See [CHANGELOG.md](CHANGELOG.md). [MIT](LICENSE) -## Support & Contact +## Contact You can ask questions on the [Gomail thread](https://groups.google.com/d/topic/golang-nuts/jMxZHzvvEVg/discussion) diff --git a/auth.go b/auth.go index b8c0dde..d28b83a 100644 --- a/auth.go +++ b/auth.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "bytes" diff --git a/auth_test.go b/auth_test.go index 604795e..428ef34 100644 --- a/auth_test.go +++ b/auth_test.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "net/smtp" diff --git a/doc.go b/doc.go index d65bf35..a8f5091 100644 --- a/doc.go +++ b/doc.go @@ -1,6 +1,5 @@ // Package gomail provides a simple interface to compose emails and to mail them // efficiently. // -// More info on Github: https://github.com/go-mail/mail -// -package mail +// More info on Github: https://github.com/go-gomail/gomail +package gomail diff --git a/example_test.go b/example_test.go index c9fd3fe..90008ab 100644 --- a/example_test.go +++ b/example_test.go @@ -1,4 +1,4 @@ -package mail_test +package gomail_test import ( "fmt" @@ -7,11 +7,11 @@ import ( "log" "time" - "gopkg.in/mail.v2" + "gopkg.in/gomail.v2" ) func Example() { - m := mail.NewMessage() + m := gomail.NewMessage() m.SetHeader("From", "alex@example.com") m.SetHeader("To", "bob@example.com", "cora@example.com") m.SetAddressHeader("Cc", "dan@example.com", "Dan") @@ -19,7 +19,7 @@ func Example() { m.SetBody("text/html", "Hello Bob and Cora!") m.Attach("/home/Alex/lolcat.jpg") - d := mail.NewDialer("smtp.example.com", 587, "user", "123456") + d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") // Send the email to Bob, Cora and Dan. if err := d.DialAndSend(m); err != nil { @@ -29,12 +29,12 @@ func Example() { // A daemon that listens to a channel and sends all incoming messages. func Example_daemon() { - ch := make(chan *mail.Message) + ch := make(chan *gomail.Message) go func() { - d := mail.NewDialer("smtp.example.com", 587, "user", "123456") + d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") - var s mail.SendCloser + var s gomail.SendCloser var err error open := false for { @@ -49,7 +49,7 @@ func Example_daemon() { } open = true } - if err := mail.Send(s, m); err != nil { + if err := gomail.Send(s, m); err != nil { log.Print(err) } // Close the connection to the SMTP server if no email was sent in @@ -79,20 +79,20 @@ func Example_newsletter() { Address string } - d := mail.NewDialer("smtp.example.com", 587, "user", "123456") + d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") s, err := d.Dial() if err != nil { panic(err) } - m := mail.NewMessage() + m := gomail.NewMessage() for _, r := range list { m.SetHeader("From", "no-reply@example.com") m.SetAddressHeader("To", r.Address, r.Name) m.SetHeader("Subject", "Newsletter #1") m.SetBody("text/html", fmt.Sprintf("Hello %s!", r.Name)) - if err := mail.Send(s, m); err != nil { + if err := gomail.Send(s, m); err != nil { log.Printf("Could not send email to %q: %v", r.Address, err) } m.Reset() @@ -101,13 +101,13 @@ func Example_newsletter() { // Send an email using a local SMTP server. func Example_noAuth() { - m := mail.NewMessage() + m := gomail.NewMessage() m.SetHeader("From", "from@example.com") m.SetHeader("To", "to@example.com") m.SetHeader("Subject", "Hello!") m.SetBody("text/plain", "Hello!") - d := mail.Dialer{Host: "localhost", Port: 587} + d := gomail.Dialer{Host: "localhost", Port: 587} if err := d.DialAndSend(m); err != nil { panic(err) } @@ -115,13 +115,13 @@ func Example_noAuth() { // Send an email using an API or postfix. func Example_noSMTP() { - m := mail.NewMessage() + m := gomail.NewMessage() m.SetHeader("From", "from@example.com") m.SetHeader("To", "to@example.com") m.SetHeader("Subject", "Hello!") m.SetBody("text/plain", "Hello!") - s := mail.SendFunc(func(from string, to []string, msg io.WriterTo) error { + s := gomail.SendFunc(func(from string, to []string, msg io.WriterTo) error { // Implements you email-sending function, for example by calling // an API, or running postfix, etc. fmt.Println("From:", from) @@ -129,7 +129,7 @@ func Example_noSMTP() { return nil }) - if err := mail.Send(s, m); err != nil { + if err := gomail.Send(s, m); err != nil { panic(err) } // Output: @@ -137,10 +137,10 @@ func Example_noSMTP() { // To: [to@example.com] } -var m *mail.Message +var m *gomail.Message func ExampleSetCopyFunc() { - m.Attach("foo.txt", mail.SetCopyFunc(func(w io.Writer) error { + m.Attach("foo.txt", gomail.SetCopyFunc(func(w io.Writer) error { _, err := w.Write([]byte("Content of foo.txt")) return err })) @@ -148,11 +148,11 @@ func ExampleSetCopyFunc() { func ExampleSetHeader() { h := map[string][]string{"Content-ID": {""}} - m.Attach("foo.jpg", mail.SetHeader(h)) + m.Attach("foo.jpg", gomail.SetHeader(h)) } func ExampleRename() { - m.Attach("/tmp/0000146.jpg", mail.Rename("picture.jpg")) + m.Attach("/tmp/0000146.jpg", gomail.Rename("picture.jpg")) } func ExampleMessage_AddAlternative() { @@ -211,13 +211,13 @@ func ExampleMessage_SetHeaders() { } func ExampleSetCharset() { - m = mail.NewMessage(mail.SetCharset("ISO-8859-1")) + m = gomail.NewMessage(gomail.SetCharset("ISO-8859-1")) } func ExampleSetEncoding() { - m = mail.NewMessage(mail.SetEncoding(mail.Base64)) + m = gomail.NewMessage(gomail.SetEncoding(gomail.Base64)) } func ExampleSetPartEncoding() { - m.SetBody("text/plain", "Hello!", mail.SetPartEncoding(mail.Unencoded)) + m.SetBody("text/plain", "Hello!", gomail.SetPartEncoding(gomail.Unencoded)) } diff --git a/message.go b/message.go index da3a308..7733e5e 100644 --- a/message.go +++ b/message.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "bytes" diff --git a/message_test.go b/message_test.go index 720c873..ea3d7f5 100644 --- a/message_test.go +++ b/message_test.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "os" diff --git a/mime.go b/mime.go index d95ea2e..194d4a7 100644 --- a/mime.go +++ b/mime.go @@ -1,6 +1,6 @@ // +build go1.5 -package mail +package gomail import ( "mime" diff --git a/mime_go14.go b/mime_go14.go index bdb605d..3dc26aa 100644 --- a/mime_go14.go +++ b/mime_go14.go @@ -1,6 +1,6 @@ // +build !go1.5 -package mail +package gomail import "gopkg.in/alexcesaro/quotedprintable.v3" diff --git a/send.go b/send.go index e14295d..99a6dd8 100644 --- a/send.go +++ b/send.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "errors" @@ -6,7 +6,6 @@ import ( "io" "net/mail" "os" - stdmail "net/mail" ) // Sender is the interface that wraps the Send method. @@ -128,7 +127,7 @@ func addAddress(list []string, addr string) []string { } func parseAddress(field string) (string, error) { - addr, err := stdmail.ParseAddress(field) + addr, err := mail.ParseAddress(field) if err != nil { return "", fmt.Errorf("gomail: invalid address %q: %v", field, err) } diff --git a/send_test.go b/send_test.go index 0e8496c..a5b426f 100644 --- a/send_test.go +++ b/send_test.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "bytes" diff --git a/smtp.go b/smtp.go index 5f3566d..2aa49c8 100644 --- a/smtp.go +++ b/smtp.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "crypto/tls" @@ -33,25 +33,17 @@ type Dialer struct { // LocalName is the hostname sent to the SMTP server with the HELO command. // By default, "localhost" is sent. LocalName string - // Timeout to use for read/write operations. Defaults to 10 seconds, can - // be set to 0 to disable timeouts. - Timeout time.Duration - // Whether we should retry mailing if the connection returned an error, - // defaults to true. - RetryFailure bool } // 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, - Timeout: 10 * time.Second, - RetryFailure: true, + Host: host, + Port: port, + Username: username, + Password: password, + SSL: port == 465, } } @@ -63,15 +55,10 @@ func NewPlainDialer(host string, port int, username, password string) *Dialer { return NewDialer(host, port, username, password) } -// NetDialTimeout specifies the DialTimeout function to establish a connection -// to the SMTP server. This can be used to override dialing in the case that a -// proxy or other special behavior is needed. -var NetDialTimeout = net.DialTimeout - // 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), d.Timeout) + conn, err := netDialTimeout("tcp", addr(d.Host, d.Port), 10*time.Second) if err != nil { return nil, err } @@ -85,10 +72,6 @@ func (d *Dialer) Dial() (SendCloser, error) { return nil, err } - if d.Timeout > 0 { - conn.SetDeadline(time.Now().Add(d.Timeout)) - } - if d.LocalName != "" { if err := c.Hello(d.LocalName); err != nil { return nil, err @@ -128,7 +111,7 @@ func (d *Dialer) Dial() (SendCloser, error) { } } - return &smtpSender{c, conn, d}, nil + return &smtpSender{c, d}, nil } func (d *Dialer) tlsConfig() *tls.Config { @@ -156,29 +139,12 @@ func (d *Dialer) DialAndSend(m ...*Message) error { type smtpSender struct { smtpClient - conn net.Conn - d *Dialer -} - -func (c *smtpSender) retryError(err error) bool { - if !c.d.RetryFailure { - return false - } - - if nerr, ok := err.(net.Error); ok && nerr.Timeout() { - return true - } - - return err == io.EOF + d *Dialer } func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error { - if c.d.Timeout > 0 { - c.conn.SetDeadline(time.Now().Add(c.d.Timeout)) - } - if err := c.Mail(from); err != nil { - if c.retryError(err) { + if err == io.EOF { // This is probably due to a timeout, so reconnect and try again. sc, derr := c.d.Dial() if derr == nil { @@ -188,7 +154,6 @@ func (c *smtpSender) Send(from string, to []string, msg io.WriterTo) error { } } } - return err } @@ -217,8 +182,9 @@ func (c *smtpSender) Close() error { // Stubbed out for tests. var ( - tlsClient = tls.Client - smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) { + netDialTimeout = net.DialTimeout + tlsClient = tls.Client + smtpNewClient = func(conn net.Conn, host string) (smtpClient, error) { return smtp.NewClient(conn, host) } ) diff --git a/smtp_test.go b/smtp_test.go index 7ed47c0..b6f9155 100644 --- a/smtp_test.go +++ b/smtp_test.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "bytes" @@ -18,7 +18,7 @@ const ( var ( testConn = &net.TCPConn{} - testTLSConn = tls.Client(testConn, &tls.Config{InsecureSkipVerify: true}) + testTLSConn = &tls.Conn{} testConfig = &tls.Config{InsecureSkipVerify: true} testAuth = smtp.PlainAuth("", testUser, testPwd, testHost) ) @@ -118,9 +118,8 @@ func TestDialerNoAuth(t *testing.T) { func TestDialerTimeout(t *testing.T) { d := &Dialer{ - Host: testHost, - Port: testPort, - RetryFailure: true, + Host: testHost, + Port: testPort, } testSendMailTimeout(t, d, []string{ "Extension STARTTLS", @@ -139,25 +138,6 @@ func TestDialerTimeout(t *testing.T) { }) } -func TestDialerTimeoutNoRetry(t *testing.T) { - d := &Dialer{ - Host: testHost, - Port: testPort, - RetryFailure: false, - } - - err := doTestSendMail(t, d, []string{ - "Extension STARTTLS", - "StartTLS", - "Mail " + testFrom, - "Quit", - }, true) - - if err.Error() != "gomail: could not send email 1: EOF" { - t.Error("expected to have got EOF, but got:", err) - } -} - type mockClient struct { t *testing.T i int @@ -252,18 +232,14 @@ func (w *mockWriter) Close() error { } func testSendMail(t *testing.T, d *Dialer, want []string) { - if err := doTestSendMail(t, d, want, false); err != nil { - t.Error(err) - } + doTestSendMail(t, d, want, false) } func testSendMailTimeout(t *testing.T, d *Dialer, want []string) { - if err := doTestSendMail(t, d, want, true); err != nil { - t.Error(err) - } + doTestSendMail(t, d, want, true) } -func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) error { +func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) { testClient := &mockClient{ t: t, want: want, @@ -272,7 +248,7 @@ func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) error timeout: timeout, } - NetDialTimeout = func(network, address string, d time.Duration) (net.Conn, error) { + netDialTimeout = func(network, address string, d time.Duration) (net.Conn, error) { if network != "tcp" { t.Errorf("Invalid network, got %q, want tcp", network) } @@ -298,7 +274,9 @@ func doTestSendMail(t *testing.T, d *Dialer, want []string, timeout bool) error return testClient, nil } - return d.DialAndSend(getTestMessage()) + if err := d.DialAndSend(getTestMessage()); err != nil { + t.Error(err) + } } func assertConfig(t *testing.T, got, want *tls.Config) { diff --git a/writeto.go b/writeto.go index 22581ab..9fb6b86 100644 --- a/writeto.go +++ b/writeto.go @@ -1,4 +1,4 @@ -package mail +package gomail import ( "encoding/base64"