diff --git a/email.go b/email.go index 57d1b53..869acc6 100644 --- a/email.go +++ b/email.go @@ -16,6 +16,7 @@ import ( "mime" "mime/multipart" "mime/quotedprintable" + "net" "net/mail" "net/smtp" "net/textproto" @@ -51,6 +52,7 @@ type Email struct { Headers textproto.MIMEHeader Attachments []*Attachment ReadReceipt []string + LocalName string // override localname for client hello negotiation } // part is a copyable representation of a multipart.Part @@ -61,7 +63,10 @@ type part struct { // NewEmail creates an Email, and returns the pointer to it. func NewEmail() *Email { - return &Email{Headers: textproto.MIMEHeader{}} + return &Email{ + Headers: textproto.MIMEHeader{}, + LocalName: "localhost", + } } // trimReader is a custom io.Reader that will trim any leading @@ -521,15 +526,58 @@ func (e *Email) Send(addr string, a smtp.Auth) error { if e.From == "" || len(to) == 0 { return errors.New("Must specify at least one From address and one To address") } - sender, err := e.parseSender() + from, err := e.parseSender() if err != nil { return err } - raw, err := e.Bytes() + msg, err := e.Bytes() + if err != nil { + return err + } + c, err := smtp.Dial(addr) + if err != nil { + return err + } + defer c.Close() + if err = c.Hello(e.LocalName); err != nil { + return err + } + if ok, _ := c.Extension("STARTTLS"); ok { + host, _, _ := net.SplitHostPort(addr) + config := &tls.Config{ServerName: host} + if err = c.StartTLS(config); err != nil { + return err + } + } + if a != nil { + if ok, _ := c.Extension("AUTH"); !ok { + return errors.New("smtp: server doesn't support AUTH") + } + if err = c.Auth(a); err != nil { + return err + } + } + if err = c.Mail(from); err != nil { + return err + } + for _, addr := range to { + if err = c.Rcpt(addr); err != nil { + return err + } + } + w, err := c.Data() if err != nil { return err } - return smtp.SendMail(addr, a, sender, to, raw) + _, err = w.Write(msg) + if err != nil { + return err + } + err = w.Close() + if err != nil { + return err + } + return c.Quit() } // Select and parse an SMTP envelope sender address. Choose Email.Sender if set, or fallback to Email.From. @@ -587,7 +635,7 @@ func (e *Email) SendWithTLS(addr string, a smtp.Auth, t *tls.Config) error { return err } defer c.Close() - if err = c.Hello("localhost"); err != nil { + if err = c.Hello(e.LocalName); err != nil { return err } @@ -656,7 +704,7 @@ func (e *Email) SendWithStartTLS(addr string, a smtp.Auth, t *tls.Config) error return err } defer c.Close() - if err = c.Hello("localhost"); err != nil { + if err = c.Hello(e.LocalName); err != nil { return err } // Use TLS if available diff --git a/email_test.go b/email_test.go index b6d62d2..88fab85 100644 --- a/email_test.go +++ b/email_test.go @@ -2,12 +2,14 @@ package email import ( "fmt" + "log" "strings" "testing" "bufio" "bytes" "crypto/rand" + "crypto/tls" "io" "io/ioutil" "mime" @@ -729,15 +731,51 @@ TGV0J3MganVzdCBwcmV0ZW5kIHRoaXMgaXMgcmF3IEpQRUcgZGF0YS4= } func ExampleGmail() { + gmUser := "test@gmail.com" + gmPass := "" + gmHost := "smtp.gmail.com" + gmPort := "587" + e := NewEmail() - e.From = "Jordan Wright " + e.From = "Jordan Wright <" + gmUser + ">" e.To = []string{"test@example.com"} e.Bcc = []string{"test_bcc@example.com"} e.Cc = []string{"test_cc@example.com"} e.Subject = "Awesome Subject" e.Text = []byte("Text Body is, of course, supported!\n") e.HTML = []byte("

Fancy Html is supported, too!

\n") - e.Send("smtp.gmail.com:587", smtp.PlainAuth("", e.From, "password123", "smtp.gmail.com")) + e.LocalName = "localhost" + err := e.Send( + gmHost+":"+gmPort, + smtp.PlainAuth("", gmUser, gmPass, gmHost), + ) + if err != nil { + log.Fatalf("Failed to send gmail mail: %v", err) + } +} + +func ExampleGmailWithTLS() { + gmUser := "test@gmail.com" + gmPass := "" + gmHost := "smtp.gmail.com" + gmPort := "465" + + e := NewEmail() + e.From = "Jordan Wright <" + gmUser + ">" + e.To = []string{"test@example.com"} + e.Bcc = []string{"test_bcc@example.com"} + e.Cc = []string{"test_cc@example.com"} + e.Subject = "Awesome Subject" + e.Text = []byte("Text Body is, of course, supported!\n") + e.HTML = []byte("

Fancy Html is supported, too!

\n") + e.LocalName = "localhost" + err := e.SendWithTLS( + gmHost+":"+gmPort, + smtp.PlainAuth("", gmUser, gmPass, gmHost), + &tls.Config{ServerName: gmHost}) + if err != nil { + log.Fatalf("Failed to send gmail mail: %v", err) + } } func ExampleAttach() {