diff --git a/.gitignore b/.gitignore index ced52f6..d786d89 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ _testmain.go *.out *.iml -.idea \ No newline at end of file +.idea + +defaults/smtp_mailer_test.json diff --git a/defaults/smtp_mailer.go b/defaults/smtp_mailer.go index 734b3fb..778ae4b 100644 --- a/defaults/smtp_mailer.go +++ b/defaults/smtp_mailer.go @@ -10,10 +10,14 @@ import ( "text/template" "time" + "github.com/pkg/errors" "github.com/volatiletech/authboss" ) // NewSMTPMailer creates an SMTP Mailer to send emails with. +// An example usage might be something like: +// +// NewSMTPMailer("smtp.gmail.com", smtp.PlainAuth("", "admin@yoursite.com", "password", "smtp.gmail.com")) func NewSMTPMailer(server string, auth smtp.Auth) *SMTPMailer { if len(server) == 0 { panic("SMTP Mailer must be created with a server string.") @@ -31,6 +35,10 @@ type SMTPMailer struct { // Send an e-mail func (s SMTPMailer) Send(ctx context.Context, mail authboss.Email) error { + if len(mail.TextBody) == 0 && len(mail.HTMLBody) == 0 { + return errors.New("refusing to send mail without text or html body") + } + buf := &bytes.Buffer{} data := struct { @@ -110,15 +118,19 @@ MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="==============={{.Boundary}}==" Content-Transfer-Encoding: 7bit +{{if .Mail.TextBody -}} --==============={{.Boundary}}== Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit {{.Mail.TextBody}} +{{end -}} +{{if .Mail.HTMLBody -}} --==============={{.Boundary}}== Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit {{.Mail.HTMLBody}} +{{end -}} --==============={{.Boundary}}==-- `)) diff --git a/defaults/smtp_mailer_test.go b/defaults/smtp_mailer_test.go index 70d0e6f..16090ce 100644 --- a/defaults/smtp_mailer_test.go +++ b/defaults/smtp_mailer_test.go @@ -1,9 +1,77 @@ package defaults -import "testing" +import ( + "context" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net/smtp" + "testing" + + "github.com/volatiletech/authboss" +) + +var ( + flagTestSMTPMailer = flag.Bool("test-smtp-mailer", false, "Test the smtp mailer") +) func TestSMTPMailer(t *testing.T) { - t.Skip("must implement test against real smtp servers here") + t.Parallel() + + if !*flagTestSMTPMailer { + t.Skip("SMTP Mailer Testing not enabled (-test-smtp-mailer flag)") + } + + creds := struct { + Server string `json:"server,omitempty"` + Port int `json:"port,omitempty"` + Email string `json:"email,omitempty"` + Password string `json:"password,omitempty"` + }{} + + b, err := ioutil.ReadFile("smtp_mailer_test.json") + if err != nil { + t.Fatal(`error reading file: "smtp_mailer_test.json`, err) + } + + if err = json.Unmarshal(b, &creds); err != nil { + t.Fatal(err) + } + + server := fmt.Sprintf("%s:%d", creds.Server, creds.Port) + mailer := NewSMTPMailer(server, smtp.PlainAuth("", creds.Email, creds.Password, creds.Server)) + + mail := authboss.Email{ + From: creds.Email, + To: []string{creds.Email}, + Subject: "Authboss Test SMTP Mailer", + } + + txtOnly := mail + txtOnly.Subject += ": Text Content" + txtOnly.TextBody = "Authboss\nSMTP\nTest\nWith\nNewlines" + + if err = mailer.Send(context.Background(), txtOnly); err != nil { + t.Error(err) + } + + htmlOnly := mail + htmlOnly.Subject += ": HTML Content" + htmlOnly.HTMLBody = "Authboss
Test
\nWith
Newlines\nand
breaks" + + if err = mailer.Send(context.Background(), htmlOnly); err != nil { + t.Error(err) + } + + mixed := mail + mixed.Subject += ": Mixed Content" + mixed.HTMLBody = htmlOnly.HTMLBody + mixed.TextBody = txtOnly.TextBody + + if err = mailer.Send(context.Background(), mixed); err != nil { + t.Error(err) + } } func TestSMTPMailerPanic(t *testing.T) {