-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmailbox.go
138 lines (115 loc) · 3.43 KB
/
mailbox.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2013 Pavel Korotkov
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mailbox
import (
"bytes"
"encoding/base64"
"fmt"
"io/ioutil"
"net/mail"
"net/smtp"
"path/filepath"
"strings"
)
const boundary = "2a1ef074a9c58c3205dd2611e439701bc68318"
type Credentials struct {
serverAddress string
auth smtp.Auth
}
func NewCredentials(serverAddress string) *Credentials {
creds := new(Credentials)
creds.serverAddress = serverAddress
return creds
}
func (creds *Credentials) SetPLAINAuth(login, password string) {
sa := strings.Split(creds.serverAddress, ":")
creds.auth = smtp.PlainAuth("", login, password, sa[0])
}
type Message struct {
from mail.Address
to []mail.Address
subject string
body string
attachments map[string][]byte
}
func (m *Message) From(name, address string) *Message {
m.from = mail.Address{name, address}
return m
}
func (m *Message) To(name, address string) *Message {
m.to = append(m.to, mail.Address{name, address})
return m
}
func (m *Message) ToMany(addressees map[string]string) *Message {
for address, name := range addressees {
m.to = append(m.to, mail.Address{name, address})
}
return m
}
func (m *Message) Subject(subject string) *Message {
m.subject = subject
return m
}
func (m *Message) Body(body string) *Message {
m.body = body
return m
}
func (m *Message) Attach(filePath string) error {
bs, err := ioutil.ReadFile(filePath)
if err != nil {
return err
}
_, fileName := filepath.Split(filePath)
if m.attachments == nil {
m.attachments = make(map[string][]byte, 3)
}
m.attachments[fileName] = bs
return nil
}
func (m *Message) getToAddresses() []string {
var addrs []string
for _, toa := range m.to {
addrs = append(addrs, toa.Address)
}
return addrs
}
func SendMessage(creds *Credentials, m *Message) error {
switch {
case creds == nil:
return fmt.Errorf("Message not sent: Input credentials must not be nil.")
case m == nil:
return fmt.Errorf("Message not sent: Input message must not be nil.")
}
buf := new(bytes.Buffer)
buf.WriteString("From: " + m.from.String() + "\n")
buf.WriteString("To: " + m.to[0].String())
for i := 1; i < len(m.to); i++ {
buf.WriteString("," + m.to[i].String())
}
buf.WriteString("\nSubject: " + strings.Trim((&mail.Address{m.subject, ""}).String(), " <>") + "\n")
buf.WriteString("MIME-Version: 1.0\n")
if m.attachments != nil {
buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\n")
buf.WriteString("--" + boundary + "\n")
}
buf.WriteString("Content-Type: text/plain; charset=\"utf-8\"\n")
buf.WriteString("Content-Transfer-Encoding: base64\n")
buf.WriteString("\n" + base64.StdEncoding.EncodeToString([]byte(m.body)))
if m.attachments != nil {
for fn, fbs := range m.attachments {
buf.WriteString("\n\n--" + boundary + "\n")
buf.WriteString("Content-Type: application/octet-stream\n")
buf.WriteString("Content-Transfer-Encoding: base64\n")
buf.WriteString("Content-Disposition: attachment; filename=\"" + fn + "\"\n\n")
b := make([]byte, base64.StdEncoding.EncodedLen(len(fbs)))
base64.StdEncoding.Encode(b, fbs)
if _, err := buf.Write(b); err != nil {
return fmt.Errorf("Could not attach %s: %s", fn, err.Error())
}
buf.WriteString("\n--" + boundary)
}
buf.WriteString("--")
}
return smtp.SendMail(creds.serverAddress, creds.auth, m.from.Address, m.getToAddresses(), buf.Bytes())
}