-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsmtp_client_config.go
194 lines (155 loc) · 4.12 KB
/
smtp_client_config.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package email
import (
"encoding/json"
"fmt"
"strings"
"time"
"crypto/tls"
"net"
"log"
"os"
)
// SMTPClientMode is the encryption mode to be used by the SMTP client
type SMTPClientMode uint8
const (
// ModeUNENCRYPTED = no encryption
ModeUNENCRYPTED SMTPClientMode = iota
// ModeSTARTTLS = STARTTLS negotiation
ModeSTARTTLS
// ModeFORCETLS = FORCED TLS
ModeFORCETLS
)
// UnmarshalJSON decodes a string into an SMTPClientConfig value.
func (mode *SMTPClientMode) UnmarshalJSON(val []byte) error {
var szStr string
E := json.Unmarshal(val, &szStr)
if E != nil {
return E
}
szStr = strings.ToUpper(strings.TrimSpace(szStr))
switch szStr {
case "UNENCRYPTED":
*mode = ModeUNENCRYPTED
case "STARTTLS":
*mode = ModeSTARTTLS
case "FORCETLS":
*mode = ModeFORCETLS
default:
return ErrInvalidSMTPMode
}
return nil
}
// SMTPClientConfig holds parameters for connecting to an SMTP server.
type SMTPClientConfig struct {
Server string
Port uint16
Username string
Password string
Mode SMTPClientMode
TimeoutMsec uint32
Proto string // dial protocol: `tcp`, `tcp4`, or `tcp6`; defaults to `tcp`
SMTPLog string // path to SMTP log: complete filepath, "-" for STDOUT, or empty to disable SMTP logging
KeepAlive net.KeepAliveConfig
}
// Dial to an SMTP server & establish an SMTP session per settings
// in SMTPClientConfig.
func (cfg SMTPClientConfig) Dial() (*Client, error) {
iAuth := LoginAuth(cfg.Username, cfg.Password)
pTLSCfg := TLSConfig(cfg.Server)
dialAddr := fmt.Sprintf("%s:%d", cfg.Server, cfg.Port)
if len(cfg.Proto) == 0 {
cfg.Proto = "tcp"
}
// FOR DIAL/IO TIMEOUTS
dTimeout := time.Millisecond * time.Duration(cfg.TimeoutMsec)
pDialer := &net.Dialer{
Timeout: dTimeout,
KeepAlive: -1,
KeepAliveConfig: cfg.KeepAlive,
}
var iConn net.Conn
var pTLSCfgClient *tls.Config
var err error
switch cfg.Mode {
case ModeSTARTTLS:
// [1]: open an unencrypted network connection
if iConn, err = pDialer.Dial(cfg.Proto, dialAddr); err != nil {
return nil, err
}
// negotiate TLS in SMTP session
pTLSCfgClient = pTLSCfg
case ModeFORCETLS:
// [1]: open a TLS-secured network connection
if iConn, err = tls.DialWithDialer(pDialer, cfg.Proto, dialAddr, pTLSCfg); err != nil {
return nil, err
}
case ModeUNENCRYPTED:
// [1]: open an unencrypted network connection
if iConn, err = pDialer.Dial(cfg.Proto, dialAddr); err != nil {
return nil, err
}
default:
return nil, ErrInvalidSMTPMode
}
var fnTextprotoCreate CreateTextprotoConnFn
// SMTP SESSION LOGGING
if len(cfg.SMTPLog) > 0 {
var pF *os.File
if cfg.SMTPLog == "-" {
pF = os.Stdout
} else {
pF, err = os.OpenFile(cfg.SMTPLog, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0660)
if err != nil {
return nil, err
}
}
fnTextprotoCreate = TextprotoLogged(log.New(pF, "", log.Ltime|log.Lmicroseconds), true)
}
// COMMS TIMEOUT
if dTimeout > 0 {
if err = iConn.SetDeadline(time.Now().Add(dTimeout)); err != nil {
return nil, err
}
}
// ESTABLISH SMTP SESSION
pCli, err := NewClient(iConn, iAuth, cfg.Server, pTLSCfgClient, fnTextprotoCreate)
if err != nil {
return nil, err
}
pCli.TimeoutMsec = cfg.TimeoutMsec
return pCli, nil
}
/*
SimpleSend is a way to quickly connect to an SMTP server, send multiple
messages, then disconnect.
Example
cfg := SMTPClientConfig{
Server: "mx.test.com",
Port: 587,
Username: "test@test.com",
Password: "...",
Mode: ModeSTARTTLS,
// SMTPLog: "-", // note: uncomment to log SMTP session to STDOUT
}
oEmail := NewEmail()
oEmail.From = "test@test.com"
oEmail.To = []string{"test_receiver@eggplant.pro"}
oEmail.Subject = "Test Message"
oEmail.Text = []byte("Whoomp there it is!")
E := cfg.SimpleSend(oEmail)
if E != nil { return E }
*/
func (cfg SMTPClientConfig) SimpleSend(sMsgs ...*Email) error {
pCli, err := cfg.Dial()
if err != nil {
return err
}
for ix := range sMsgs {
if err = pCli.Send(sMsgs[ix]); err != nil {
return err
}
}
// CLOSE SMTP SESSION WHEN FINISHED SENDING
// NOTE: this also closes the underlying network connection
return pCli.Quit()
}