Эх сурвалжийг харах

Allow a custom envelope sender (overriding e.From) for bounce handling, etc. (#52)

Allow a custom envelope sender (overriding e.From) for bounce handling, etc.
Jeremy Wohl 7 жил өмнө
parent
commit
473746f012
2 өөрчлөгдсөн 59 нэмэгдсэн , 5 устгасан
  1. 22 4
      email.go
  2. 37 1
      email_test.go

+ 22 - 4
email.go

@@ -46,6 +46,7 @@ type Email struct {
 	Subject     string
 	Text        []byte // Plaintext message (optional)
 	HTML        []byte // Html message (optional)
+	Sender      string // override From as SMTP envelope sender (optional)
 	Headers     textproto.MIMEHeader
 	Attachments []*Attachment
 	ReadReceipt []string
@@ -403,7 +404,7 @@ 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")
 	}
-	from, err := mail.ParseAddress(e.From)
+	sender, err := e.parseSender()
 	if err != nil {
 		return err
 	}
@@ -411,7 +412,24 @@ func (e *Email) Send(addr string, a smtp.Auth) error {
 	if err != nil {
 		return err
 	}
-	return smtp.SendMail(addr, a, from.Address, to, raw)
+	return smtp.SendMail(addr, a, sender, to, raw)
+}
+
+// Select and parse an SMTP envelope sender address.  Choose Email.Sender if set, or fallback to Email.From.
+func (e *Email) parseSender() (string, error) {
+	if e.Sender != "" {
+		sender, err := mail.ParseAddress(e.Sender)
+		if err != nil {
+			return "", err
+		}
+		return sender.Address, nil
+	} else {
+		from, err := mail.ParseAddress(e.From)
+		if err != nil {
+			return "", err
+		}
+		return from.Address, nil
+	}
 }
 
 // SendWithTLS sends an email with an optional TLS config.
@@ -432,7 +450,7 @@ func (e *Email) SendWithTLS(addr string, a smtp.Auth, t *tls.Config) error {
 	if e.From == "" || len(to) == 0 {
 		return errors.New("Must specify at least one From address and one To address")
 	}
-	from, err := mail.ParseAddress(e.From)
+	sender, err := e.parseSender()
 	if err != nil {
 		return err
 	}
@@ -464,7 +482,7 @@ func (e *Email) SendWithTLS(addr string, a smtp.Auth, t *tls.Config) error {
 			}
 		}
 	}
-	if err = c.Mail(from.Address); err != nil {
+	if err = c.Mail(sender); err != nil {
 		return err
 	}
 	for _, addr := range to {

+ 37 - 1
email_test.go

@@ -306,7 +306,7 @@ func TestNonMultipartEmailFromReader(t *testing.T) {
 	ex.Headers.Add("Message-ID", "<foobar@example.com>")
 	raw := []byte(`From: "Foo Bar" <foobar@example.com>
 Content-Type: text/plain
-To: foobar@example.com 
+To: foobar@example.com
 Subject: Example Subject (no MIME Type)
 Message-ID: <foobar@example.com>
 
@@ -471,3 +471,39 @@ func Benchmark_base64Wrap(b *testing.B) {
 		base64Wrap(ioutil.Discard, file)
 	}
 }
+
+func TestParseSender(t *testing.T) {
+	var cases = []struct {
+		e      Email
+		want   string
+		haserr bool
+	}{
+		{
+			Email{From: "from@test.com"},
+			"from@test.com",
+			false,
+		},
+		{
+			Email{Sender: "sender@test.com", From: "from@test.com"},
+			"sender@test.com",
+			false,
+		},
+		{
+			Email{Sender: "bad_address_sender"},
+			"",
+			true,
+		},
+		{
+			Email{Sender: "good@sender.com", From: "bad_address_from"},
+			"good@sender.com",
+			false,
+		},
+	}
+
+	for i, testcase := range cases {
+		got, err := testcase.e.parseSender()
+		if got != testcase.want || (err != nil) != testcase.haserr {
+			t.Errorf(`%d: got %s != want %s or error "%t" != "%t"`, i+1, got, testcase.want, err != nil, testcase.haserr)
+		}
+	}
+}