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:
parent
4b313106fd
commit
8de74d4f48
|
@ -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
54
send.go
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue