2022-03-09 16:52:23 +01:00
|
|
|
package mail
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
2022-03-10 16:19:51 +01:00
|
|
|
"net/mail"
|
2022-03-09 16:52:23 +01:00
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Msg is the mail message struct
|
|
|
|
type Msg struct {
|
|
|
|
// charset represents the charset of the mail (defaults to UTF-8)
|
|
|
|
charset string
|
|
|
|
|
|
|
|
// encoder represents a mime.WordEncoder from the std lib
|
2022-03-09 17:05:38 +01:00
|
|
|
//encoder mime.WordEncoder
|
2022-03-09 16:52:23 +01:00
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// genHeader is a slice of strings that the different generic mail Header fields
|
|
|
|
genHeader map[Header][]string
|
|
|
|
|
|
|
|
// addrHeader is a slice of strings that the different mail AddrHeader fields
|
|
|
|
addrHeader map[AddrHeader][]*mail.Address
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewMsg returns a new Msg pointer
|
|
|
|
func NewMsg() *Msg {
|
|
|
|
m := &Msg{
|
2022-03-10 16:19:51 +01:00
|
|
|
charset: "UTF-8",
|
|
|
|
genHeader: make(map[Header][]string),
|
|
|
|
addrHeader: make(map[AddrHeader][]*mail.Address),
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// SetHeader sets a generic header field of the Msg
|
2022-03-09 16:52:23 +01:00
|
|
|
func (m *Msg) SetHeader(h Header, v ...string) {
|
2022-03-10 16:19:51 +01:00
|
|
|
m.genHeader[h] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetAddrHeader sets an address related header field of the Msg
|
|
|
|
func (m *Msg) SetAddrHeader(h AddrHeader, v ...string) error {
|
|
|
|
var al []*mail.Address
|
|
|
|
for _, av := range v {
|
|
|
|
a, err := mail.ParseAddress(av)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to parse mail address header %q: %w", av, err)
|
|
|
|
}
|
|
|
|
al = append(al, a)
|
|
|
|
}
|
2022-03-09 16:52:23 +01:00
|
|
|
switch h {
|
|
|
|
case HeaderFrom:
|
2022-03-10 16:19:51 +01:00
|
|
|
m.addrHeader[h] = []*mail.Address{al[0]}
|
2022-03-09 16:52:23 +01:00
|
|
|
default:
|
2022-03-10 16:19:51 +01:00
|
|
|
m.addrHeader[h] = al
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
2022-03-10 16:19:51 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetAddrHeaderIgnoreInvalid sets an address related header field of the Msg and ignores invalid address
|
|
|
|
// in the validation process
|
|
|
|
func (m *Msg) SetAddrHeaderIgnoreInvalid(h AddrHeader, v ...string) {
|
|
|
|
var al []*mail.Address
|
|
|
|
for _, av := range v {
|
|
|
|
a, err := mail.ParseAddress(av)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
al = append(al, a)
|
|
|
|
}
|
|
|
|
m.addrHeader[h] = al
|
|
|
|
}
|
|
|
|
|
|
|
|
// From takes and validates a given mail address and sets it as "From" genHeader of the Msg
|
|
|
|
func (m *Msg) From(f string) error {
|
|
|
|
return m.SetAddrHeader(HeaderFrom, f)
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// To takes and validates a given mail address list sets the To: addresses of the Msg
|
|
|
|
func (m *Msg) To(t ...string) error {
|
|
|
|
return m.SetAddrHeader(HeaderTo, t...)
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// ToIgnoreInvalid takes and validates a given mail address list sets the To: addresses of the Msg
|
|
|
|
// Any provided address that is not RFC5322 compliant, will be ignored
|
|
|
|
func (m *Msg) ToIgnoreInvalid(t ...string) {
|
|
|
|
m.SetAddrHeaderIgnoreInvalid(HeaderTo, t...)
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// Cc takes and validates a given mail address list sets the Cc: addresses of the Msg
|
|
|
|
func (m *Msg) Cc(c ...string) error {
|
|
|
|
return m.SetAddrHeader(HeaderCc, c...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// CcIgnoreInvalid takes and validates a given mail address list sets the Cc: addresses of the Msg
|
|
|
|
// Any provided address that is not RFC5322 compliant, will be ignored
|
|
|
|
func (m *Msg) CcIgnoreInvalid(c ...string) {
|
|
|
|
m.SetAddrHeaderIgnoreInvalid(HeaderCc, c...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bcc takes and validates a given mail address list sets the Bcc: addresses of the Msg
|
|
|
|
func (m *Msg) Bcc(b ...string) error {
|
|
|
|
return m.SetAddrHeader(HeaderBcc, b...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// BccIgnoreInvalid takes and validates a given mail address list sets the Bcc: addresses of the Msg
|
|
|
|
// Any provided address that is not RFC5322 compliant, will be ignored
|
|
|
|
func (m *Msg) BccIgnoreInvalid(b ...string) {
|
|
|
|
m.SetAddrHeaderIgnoreInvalid(HeaderBcc, b...)
|
2022-03-09 16:52:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetMessageID generates a random message id for the mail
|
|
|
|
func (m *Msg) SetMessageID() {
|
|
|
|
hn, err := os.Hostname()
|
|
|
|
if err != nil {
|
|
|
|
hn = "localhost.localdomain"
|
|
|
|
}
|
|
|
|
ct := time.Now().UnixMicro()
|
|
|
|
r := rand.New(rand.NewSource(ct))
|
|
|
|
rn := r.Int()
|
|
|
|
pid := os.Getpid()
|
|
|
|
|
|
|
|
mid := fmt.Sprintf("%d.%d.%d@%s", pid, rn, ct, hn)
|
|
|
|
m.SetMessageIDWithValue(mid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetMessageIDWithValue sets the message id for the mail
|
|
|
|
func (m *Msg) SetMessageIDWithValue(v string) {
|
|
|
|
m.SetHeader(HeaderMessageID, v)
|
|
|
|
}
|
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// SetBulk sets the "Precedence: bulk" genHeader which is recommended for
|
2022-03-09 16:52:23 +01:00
|
|
|
// automated mails like OOO replies
|
|
|
|
// See: https://www.rfc-editor.org/rfc/rfc2076#section-3.9
|
|
|
|
func (m *Msg) SetBulk() {
|
|
|
|
m.SetHeader(HeaderPrecedence, "bulk")
|
|
|
|
}
|
|
|
|
|
2022-03-10 16:19:51 +01:00
|
|
|
// SetDate sets the Date genHeader field to the current time in a valid format
|
|
|
|
func (m *Msg) SetDate() {
|
|
|
|
ts := time.Now().Format(time.RFC1123Z)
|
|
|
|
m.SetHeader(HeaderDate, ts)
|
|
|
|
}
|
|
|
|
|
2022-03-10 12:10:27 +01:00
|
|
|
// Header does something
|
|
|
|
// FIXME: This is only here to quickly show the set headers for debugging purpose. Remove me later
|
2022-03-09 16:52:23 +01:00
|
|
|
func (m *Msg) Header() {
|
2022-03-10 16:19:51 +01:00
|
|
|
fmt.Printf("Address header: %+v\n", m.addrHeader)
|
|
|
|
fmt.Printf("Generic header: %+v\n", m.genHeader)
|
2022-03-09 16:52:23 +01:00
|
|
|
|
|
|
|
}
|