Removed the Bcc header field when sending emails

This way of handling Bcc field is described in RFC 5322 section 3.6.3:
https://tools.ietf.org/html/rfc5322#section-3.6.3

It makes the code much more simple and efficient.
This commit is contained in:
Alexandre Cesaro 2015-07-02 21:10:45 +02:00
parent 4b313106fd
commit 8de74d4f48
2 changed files with 34 additions and 91 deletions

View File

@ -38,7 +38,7 @@ func TestMessage(t *testing.T) {
}) })
msg.SetBody("text/plain", "¡Hola, señor!") msg.SetBody("text/plain", "¡Hola, señor!")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{ to: []string{
"to@example.com", "to@example.com",
@ -69,7 +69,7 @@ func TestBodyWriter(t *testing.T) {
w := msg.GetBodyWriter("text/plain") w := msg.GetBodyWriter("text/plain")
w.Write([]byte("Test message")) w.Write([]byte("Test message"))
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -92,7 +92,7 @@ func TestCustomMessage(t *testing.T) {
}) })
msg.SetBody("text/html", "¡Hola, señor!") msg.SetBody("text/html", "¡Hola, señor!")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -116,7 +116,7 @@ func TestUnencodedMessage(t *testing.T) {
}) })
msg.SetBody("text/html", "¡Hola, señor!") msg.SetBody("text/html", "¡Hola, señor!")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -142,9 +142,9 @@ func TestRecipients(t *testing.T) {
}) })
msg.SetBody("text/plain", "Test message") msg.SetBody("text/plain", "Test message")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com", "cc@example.com"}, to: []string{"to@example.com", "cc@example.com", "bcc1@example.com", "bcc2@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
"To: to@example.com\r\n" + "To: to@example.com\r\n" +
"Cc: cc@example.com\r\n" + "Cc: cc@example.com\r\n" +
@ -154,34 +154,8 @@ func TestRecipients(t *testing.T) {
"\r\n" + "\r\n" +
"Test message", "Test message",
} }
wantBcc1 := message{
from: "from@example.com",
to: []string{"bcc1@example.com"},
content: "From: from@example.com\r\n" +
"To: to@example.com\r\n" +
"Cc: cc@example.com\r\n" +
"Bcc: bcc1@example.com\r\n" +
"Subject: Hello!\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"Content-Transfer-Encoding: quoted-printable\r\n" +
"\r\n" +
"Test message",
}
wantBcc2 := message{
from: "from@example.com",
to: []string{"bcc2@example.com"},
content: "From: from@example.com\r\n" +
"To: to@example.com\r\n" +
"Cc: cc@example.com\r\n" +
"Bcc: bcc2@example.com\r\n" +
"Subject: Hello!\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"Content-Transfer-Encoding: quoted-printable\r\n" +
"\r\n" +
"Test message",
}
testMessage(t, msg, 0, want, wantBcc1, wantBcc2) testMessage(t, msg, 0, want)
} }
func TestAlternative(t *testing.T) { func TestAlternative(t *testing.T) {
@ -191,7 +165,7 @@ func TestAlternative(t *testing.T) {
msg.SetBody("text/plain", "¡Hola, señor!") msg.SetBody("text/plain", "¡Hola, señor!")
msg.AddAlternative("text/html", "¡<b>Hola</b>, <i>señor</i>!</h1>") msg.AddAlternative("text/html", "¡<b>Hola</b>, <i>señor</i>!</h1>")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -228,7 +202,7 @@ func TestAttachmentOnly(t *testing.T) {
} }
msg.Attach(f) msg.Attach(f)
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -250,7 +224,7 @@ func TestAttachment(t *testing.T) {
msg.SetBody("text/plain", "Test") msg.SetBody("text/plain", "Test")
msg.Attach(CreateFile("test.pdf", []byte("Content"))) msg.Attach(CreateFile("test.pdf", []byte("Content")))
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -281,7 +255,7 @@ func TestAttachmentsOnly(t *testing.T) {
msg.Attach(CreateFile("test.pdf", []byte("Content 1"))) msg.Attach(CreateFile("test.pdf", []byte("Content 1")))
msg.Attach(CreateFile("test.zip", []byte("Content 2"))) msg.Attach(CreateFile("test.zip", []byte("Content 2")))
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -314,7 +288,7 @@ func TestAttachments(t *testing.T) {
msg.Attach(CreateFile("test.pdf", []byte("Content 1"))) msg.Attach(CreateFile("test.pdf", []byte("Content 1")))
msg.Attach(CreateFile("test.zip", []byte("Content 2"))) msg.Attach(CreateFile("test.zip", []byte("Content 2")))
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -354,7 +328,7 @@ func TestEmbedded(t *testing.T) {
msg.Embed(CreateFile("image2.jpg", []byte("Content 2"))) msg.Embed(CreateFile("image2.jpg", []byte("Content 2")))
msg.SetBody("text/plain", "Test") msg.SetBody("text/plain", "Test")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -395,7 +369,7 @@ func TestFullMessage(t *testing.T) {
msg.Attach(CreateFile("test.pdf", []byte("Content 1"))) msg.Attach(CreateFile("test.pdf", []byte("Content 1")))
msg.Embed(CreateFile("image.jpg", []byte("Content 2"))) msg.Embed(CreateFile("image.jpg", []byte("Content 2")))
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -454,7 +428,7 @@ func TestQpLineLength(t *testing.T) {
strings.Repeat("0", 75)+"\r\n"+ strings.Repeat("0", 75)+"\r\n"+
strings.Repeat("0", 76)+"\n") strings.Repeat("0", 76)+"\n")
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -480,7 +454,7 @@ func TestBase64LineLength(t *testing.T) {
msg.SetHeader("To", "to@example.com") msg.SetHeader("To", "to@example.com")
msg.SetBody("text/plain", strings.Repeat("0", 58)) msg.SetBody("text/plain", strings.Repeat("0", 58))
want := message{ want := &message{
from: "from@example.com", from: "from@example.com",
to: []string{"to@example.com"}, to: []string{"to@example.com"},
content: "From: from@example.com\r\n" + content: "From: from@example.com\r\n" +
@ -494,21 +468,15 @@ func TestBase64LineLength(t *testing.T) {
testMessage(t, msg, 0, want) testMessage(t, msg, 0, want)
} }
func testMessage(t *testing.T, msg *Message, bCount int, emails ...message) { func testMessage(t *testing.T, msg *Message, bCount int, want *message) {
err := Send(stubSendMail(t, bCount, emails...), msg) err := Send(stubSendMail(t, bCount, want), msg)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
} }
func stubSendMail(t *testing.T, bCount int, emails ...message) SendFunc { func stubSendMail(t *testing.T, bCount int, want *message) SendFunc {
i := 0
return func(from string, to []string, msg io.Reader) error { return func(from string, to []string, msg io.Reader) error {
if i > len(emails) {
t.Fatalf("Only %d mails should be sent", len(emails))
}
want := emails[i]
if from != want.from { if from != want.from {
t.Fatalf("Invalid from, got %q, want %q", from, want.from) t.Fatalf("Invalid from, got %q, want %q", from, want.from)
} }
@ -541,7 +509,6 @@ func stubSendMail(t *testing.T, bCount int, emails ...message) SendFunc {
wantMsg = strings.Replace(wantMsg, "_BOUNDARY_"+strconv.Itoa(i+1)+"_", b, -1) wantMsg = strings.Replace(wantMsg, "_BOUNDARY_"+strconv.Itoa(i+1)+"_", b, -1)
} }
} }
i++
compareBodies(t, got, wantMsg) compareBodies(t, got, wantMsg)

54
send.go
View File

@ -52,34 +52,26 @@ func send(s Sender, msg *Message) error {
if err != nil { if err != nil {
return err return err
} }
recipients, bcc, err := getRecipients(message) to, err := getRecipients(message)
if err != nil { if err != nil {
return err return err
} }
h := flattenHeader(message, "") h := flattenHeader(message)
body, err := ioutil.ReadAll(message.Body) body, err := ioutil.ReadAll(message.Body)
if err != nil { if err != nil {
return err return err
} }
mail := bytes.NewReader(append(h, body...)) mail := bytes.NewReader(append(h, body...))
if err := s.Send(from, recipients, mail); err != nil { if err := s.Send(from, to, mail); err != nil {
return err return err
} }
for _, to := range bcc {
h = flattenHeader(message, to)
mail = bytes.NewReader(append(h, body...))
if err := s.Send(from, []string{to}, mail); err != nil {
return err
}
}
return nil return nil
} }
func flattenHeader(msg *mail.Message, bcc string) []byte { func flattenHeader(msg *mail.Message) []byte {
buf := getBuffer() buf := getBuffer()
defer putBuffer(buf) defer putBuffer(buf)
@ -89,15 +81,6 @@ func flattenHeader(msg *mail.Message, bcc string) []byte {
buf.WriteString(": ") buf.WriteString(": ")
buf.WriteString(strings.Join(value, ", ")) buf.WriteString(strings.Join(value, ", "))
buf.WriteString("\r\n") buf.WriteString("\r\n")
} else if bcc != "" {
for _, to := range value {
if strings.Contains(to, bcc) {
buf.WriteString(field)
buf.WriteString(": ")
buf.WriteString(to)
buf.WriteString("\r\n")
}
}
} }
} }
buf.WriteString("\r\n") buf.WriteString("\r\n")
@ -117,38 +100,31 @@ func getFrom(msg *mail.Message) (string, error) {
return parseAddress(from) return parseAddress(from)
} }
func getRecipients(msg *mail.Message) (recipients, bcc []string, err error) { func getRecipients(msg *mail.Message) ([]string, error) {
for _, field := range []string{"Bcc", "To", "Cc"} { var list []string
for _, field := range []string{"To", "Cc", "Bcc"} {
if addresses, ok := msg.Header[field]; ok { if addresses, ok := msg.Header[field]; ok {
for _, addr := range addresses { for _, a := range addresses {
switch field { addr, err := parseAddress(a)
case "Bcc":
bcc, err = addAdress(bcc, addr)
default:
recipients, err = addAdress(recipients, addr)
}
if err != nil { if err != nil {
return recipients, bcc, err return nil, err
} }
list = addAdress(list, addr)
} }
} }
} }
return recipients, bcc, nil return list, nil
} }
func addAdress(list []string, addr string) ([]string, error) { func addAdress(list []string, addr string) []string {
addr, err := parseAddress(addr)
if err != nil {
return list, err
}
for _, a := range list { for _, a := range list {
if addr == a { if addr == a {
return list, nil return list
} }
} }
return append(list, addr), nil return append(list, addr)
} }
func parseAddress(field string) (string, error) { func parseAddress(field string) (string, error) {