-
Notifications
You must be signed in to change notification settings - Fork 13
/
daemon.go
100 lines (87 loc) · 2.55 KB
/
daemon.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
package mailout
import (
"crypto/tls"
"net/http"
"time"
"gopkg.in/gomail.v2"
)
func startMailDaemon(mc *config) chan<- *http.Request {
rChan := make(chan *http.Request)
// this can be a bottleneck under high load because the channel is unbuffered.
// maybe we can add a pool of sendmail workers.
go goMailDaemonRecoverable(mc, rChan)
return rChan
}
// goMailDaemonRecoverable self restarting goroutine.
// TODO(cs) limit restarting to e.g. 10 tries and then crash it.
func goMailDaemonRecoverable(mc *config, rChan <-chan *http.Request) {
defer func() {
if r := recover(); r != nil {
mc.maillog.Errorf("[mailout] Catching panic %#v and restarting daemon ...", r)
go goMailDaemonRecoverable(mc, rChan)
}
}()
goMailDaemon(mc, rChan)
}
func goMailDaemon(mc *config, rChan <-chan *http.Request) {
d := gomail.NewDialer(mc.host, mc.port, mc.username, mc.password)
if mc.port == 587 {
d.TLSConfig = &tls.Config{
ServerName: mc.host, // host names must match between this one and the one requested in the cert.
}
}
if mc.skipTLSVerify {
if d.TLSConfig == nil {
d.TLSConfig = &tls.Config{}
}
d.TLSConfig.InsecureSkipVerify = true
}
var s gomail.SendCloser
var err error
open := false
for {
select {
case r, ok := <-rChan:
if !ok {
return
}
mails := newMessage(mc, r).build()
// multiple mails will increase the rate limit at some MTAs.
// so the REST API rate limit must be: rate / pgpEmailAddresses
if !open {
if s, err = d.Dial(); err != nil {
mc.maillog.Errorf("Dial Error: %s", err)
wc := mc.maillog.NewWriter()
if _, errW := mails.WriteTo(wc); errW != nil {
mc.maillog.Errorf("Dial: Message WriteTo Log Error: %s", errW)
}
if errC := wc.Close(); errC != nil {
mc.maillog.Errorf("Dial wc.Close Error: %s", errC)
}
continue
}
open = true
}
wc := mc.maillog.NewWriter()
if _, err2 := mails.WriteTo(wc); err2 != nil {
mc.maillog.Errorf("Send: Message WriteTo Log Error: %s", err)
}
if err = wc.Close(); err != nil {
mc.maillog.Errorf("Send wc.Close Error: %s", err)
}
if err := gomail.Send(s, mails...); err != nil {
mc.maillog.Errorf("Send Error: %s", err)
}
// Close the connection to the SMTP server if no email was sent in
// the last 30 seconds.
case <-time.After(30 * time.Second):
if open {
if err := s.Close(); err != nil {
mc.maillog.Errorf("Dial Close Error: %s", err)
}
open = false
}
//default: // http://www.jtolds.com/writing/2016/03/go-channels-are-bad-and-you-should-feel-bad/
}
}
}