2014-10-22 23:47:24 +08:00
|
|
|
package gomail
|
|
|
|
|
|
|
|
import (
|
2015-06-30 17:55:03 +08:00
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2014-10-22 23:47:24 +08:00
|
|
|
"io"
|
2015-06-30 17:55:03 +08:00
|
|
|
"io/ioutil"
|
|
|
|
"net/mail"
|
|
|
|
"strings"
|
2014-10-22 23:47:24 +08:00
|
|
|
)
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
// Sender is the interface that wraps the Send method.
|
|
|
|
//
|
|
|
|
// Send sends an email to the given addresses.
|
|
|
|
type Sender interface {
|
|
|
|
Send(from string, to []string, msg io.Reader) error
|
|
|
|
}
|
2014-10-22 23:47:24 +08:00
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
// SendCloser is the interface that groups the Send and Close methods.
|
|
|
|
type SendCloser interface {
|
|
|
|
Sender
|
|
|
|
Close() error
|
|
|
|
}
|
2014-10-22 23:47:24 +08:00
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
// A SendFunc is a function that sends emails to the given adresses.
|
|
|
|
// The SendFunc type is an adapter to allow the use of ordinary functions as
|
|
|
|
// email senders. If f is a function with the appropriate signature, SendFunc(f)
|
|
|
|
// is a Sender object that calls f.
|
|
|
|
type SendFunc func(from string, to []string, msg io.Reader) error
|
2014-10-22 23:47:24 +08:00
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
// Send calls f(from, to, msg).
|
|
|
|
func (f SendFunc) Send(from string, to []string, msg io.Reader) error {
|
|
|
|
return f(from, to, msg)
|
|
|
|
}
|
2014-10-22 23:47:24 +08:00
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
// Send sends emails using the given Sender.
|
|
|
|
func Send(s Sender, msg ...*Message) error {
|
|
|
|
for i, m := range msg {
|
|
|
|
if err := send(s, m); err != nil {
|
|
|
|
return fmt.Errorf("gomail: could not send email %d: %v", i+1, err)
|
2014-10-22 23:47:24 +08:00
|
|
|
}
|
|
|
|
}
|
2015-06-30 17:55:03 +08:00
|
|
|
|
|
|
|
return nil
|
2014-10-22 23:47:24 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
func send(s Sender, msg *Message) error {
|
|
|
|
message := msg.Export()
|
|
|
|
|
|
|
|
from, err := getFrom(message)
|
2014-10-22 23:55:36 +08:00
|
|
|
if err != nil {
|
2015-06-30 17:55:03 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
recipients, bcc, err := getRecipients(message)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2014-10-22 23:55:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
h := flattenHeader(message, "")
|
|
|
|
body, err := ioutil.ReadAll(message.Body)
|
2014-10-22 23:55:36 +08:00
|
|
|
if err != nil {
|
2015-06-30 17:55:03 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
mail := bytes.NewReader(append(h, body...))
|
|
|
|
if err := s.Send(from, recipients, mail); err != nil {
|
|
|
|
return err
|
2014-10-22 23:55:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
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
|
|
|
|
}
|
2014-10-22 23:55:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
return nil
|
2014-10-22 23:55:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
func flattenHeader(msg *mail.Message, bcc string) []byte {
|
|
|
|
buf := getBuffer()
|
|
|
|
defer putBuffer(buf)
|
|
|
|
|
|
|
|
for field, value := range msg.Header {
|
|
|
|
if field != "Bcc" {
|
|
|
|
buf.WriteString(field)
|
|
|
|
buf.WriteString(": ")
|
|
|
|
buf.WriteString(strings.Join(value, ", "))
|
|
|
|
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")
|
|
|
|
|
|
|
|
return buf.Bytes()
|
2014-10-22 23:47:24 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
func getFrom(msg *mail.Message) (string, error) {
|
|
|
|
from := msg.Header.Get("Sender")
|
|
|
|
if from == "" {
|
|
|
|
from = msg.Header.Get("From")
|
|
|
|
if from == "" {
|
2015-06-30 21:41:51 +08:00
|
|
|
return "", errors.New("gomail: invalid message, \"From\" field is absent")
|
2015-06-30 17:55:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return parseAddress(from)
|
2014-10-22 23:55:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
func getRecipients(msg *mail.Message) (recipients, bcc []string, err error) {
|
|
|
|
for _, field := range []string{"Bcc", "To", "Cc"} {
|
|
|
|
if addresses, ok := msg.Header[field]; ok {
|
|
|
|
for _, addr := range addresses {
|
|
|
|
switch field {
|
|
|
|
case "Bcc":
|
|
|
|
bcc, err = addAdress(bcc, addr)
|
|
|
|
default:
|
|
|
|
recipients, err = addAdress(recipients, addr)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return recipients, bcc, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return recipients, bcc, nil
|
2014-10-22 23:55:36 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 17:55:03 +08:00
|
|
|
func addAdress(list []string, addr string) ([]string, error) {
|
|
|
|
addr, err := parseAddress(addr)
|
|
|
|
if err != nil {
|
|
|
|
return list, err
|
|
|
|
}
|
|
|
|
for _, a := range list {
|
|
|
|
if addr == a {
|
|
|
|
return list, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return append(list, addr), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseAddress(field string) (string, error) {
|
|
|
|
a, err := mail.ParseAddress(field)
|
|
|
|
if a == nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return a.Address, err
|
2014-10-22 23:47:24 +08:00
|
|
|
}
|