1package gomail
2
3import (
4	"errors"
5	"fmt"
6	"io"
7	"net/mail"
8)
9
10// Sender is the interface that wraps the Send method.
11//
12// Send sends an email to the given addresses.
13type Sender interface {
14	Send(from string, to []string, msg io.WriterTo) error
15}
16
17// SendCloser is the interface that groups the Send and Close methods.
18type SendCloser interface {
19	Sender
20	Close() error
21}
22
23// A SendFunc is a function that sends emails to the given addresses.
24//
25// The SendFunc type is an adapter to allow the use of ordinary functions as
26// email senders. If f is a function with the appropriate signature, SendFunc(f)
27// is a Sender object that calls f.
28type SendFunc func(from string, to []string, msg io.WriterTo) error
29
30// Send calls f(from, to, msg).
31func (f SendFunc) Send(from string, to []string, msg io.WriterTo) error {
32	return f(from, to, msg)
33}
34
35// Send sends emails using the given Sender.
36func Send(s Sender, msg ...*Message) error {
37	for i, m := range msg {
38		if err := send(s, m); err != nil {
39			return fmt.Errorf("gomail: could not send email %d: %v", i+1, err)
40		}
41	}
42
43	return nil
44}
45
46func send(s Sender, m *Message) error {
47	from, err := m.getFrom()
48	if err != nil {
49		return err
50	}
51
52	to, err := m.getRecipients()
53	if err != nil {
54		return err
55	}
56
57	if err := s.Send(from, to, m); err != nil {
58		return err
59	}
60
61	return nil
62}
63
64func (m *Message) getFrom() (string, error) {
65	from := m.header["Sender"]
66	if len(from) == 0 {
67		from = m.header["From"]
68		if len(from) == 0 {
69			return "", errors.New(`gomail: invalid message, "From" field is absent`)
70		}
71	}
72
73	return parseAddress(from[0])
74}
75
76func (m *Message) getRecipients() ([]string, error) {
77	n := 0
78	for _, field := range []string{"To", "Cc", "Bcc"} {
79		if addresses, ok := m.header[field]; ok {
80			n += len(addresses)
81		}
82	}
83	list := make([]string, 0, n)
84
85	for _, field := range []string{"To", "Cc", "Bcc"} {
86		if addresses, ok := m.header[field]; ok {
87			for _, a := range addresses {
88				addr, err := parseAddress(a)
89				if err != nil {
90					return nil, err
91				}
92				list = addAddress(list, addr)
93			}
94		}
95	}
96
97	return list, nil
98}
99
100func addAddress(list []string, addr string) []string {
101	for _, a := range list {
102		if addr == a {
103			return list
104		}
105	}
106
107	return append(list, addr)
108}
109
110func parseAddress(field string) (string, error) {
111	addr, err := mail.ParseAddress(field)
112	if err != nil {
113		return "", fmt.Errorf("gomail: invalid address %q: %v", field, err)
114	}
115	return addr.Address, nil
116}
117