-
Notifications
You must be signed in to change notification settings - Fork 6
/
mta.go
101 lines (98 loc) · 2.75 KB
/
mta.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
package sendmail
import (
"errors"
"net"
"net/smtp"
"strings"
"sync/atomic"
)
// SendLikeMTA message delivery directly, like Mail Transfer Agent.
func (e *Envelope) SendLikeMTA() <-chan Result {
var successCount = new(int32)
mapDomains := make(map[string][]string)
results := make(chan Result, len(e.Recipients))
generatedBody, err := e.GenerateMessage()
if err != nil {
results <- Result{FatalLevel, err, "Generate message", nil}
} else {
for _, recipient := range e.Recipients {
domain := GetDomainFromAddress(recipient)
mapDomains[domain] = append(mapDomains[domain], recipient)
}
for domain, addresses := range mapDomains {
rcpts := strings.Join(addresses, ",")
wg.Add(1)
go func(domain string, addresses []string) {
defer wg.Done()
var hostList []string
mxrecords, err := net.LookupMX(domain)
if err != nil {
results <- Result{WarnLevel, err, "LookupMX", Fields{
"sender": e.Header.Get("From"),
"domain": domain,
"recipients": rcpts,
}}
// Fallback to A records
ips, err := net.LookupIP(domain)
if err != nil {
results <- Result{WarnLevel, err, "LookupIP", Fields{
"sender": e.Header.Get("From"),
"domain": domain,
"recipients": rcpts,
}}
} else {
for _, ip := range ips {
host := strings.TrimSuffix(ip.String(), ".")
hostList = append(hostList, host)
}
}
} else {
for _, mx := range mxrecords {
host := strings.TrimSuffix(mx.Host, ".")
hostList = append(hostList, host)
}
}
if len(hostList) == 0 {
results <- Result{ErrorLevel, errors.New("MX not found"), "Lookup", Fields{
"sender": e.Header.Get("From"),
"domain": domain,
"recipients": rcpts,
}}
} else {
for _, host := range hostList {
fields := Fields{
"sender": e.Header.Get("From"),
"mx": host,
"recipients": rcpts,
}
err := smtp.SendMail(host+":"+e.PortSMTP, nil,
e.Header.Get("From"),
addresses,
generatedBody)
if err == nil {
results <- Result{InfoLevel, nil, "Send mail OK", fields}
atomic.AddInt32(successCount, 1)
return
}
results <- Result{WarnLevel, err, "", fields}
}
}
}(domain, addresses)
}
}
go func() {
wg.Wait()
fields := Fields{
"sender": e.Header.Get("From"),
"success": *successCount,
"total": int32(len(mapDomains)),
}
if *successCount == 0 {
results <- Result{ErrorLevel, errors.New("failed to deliver to all recipients"), "", fields}
} else if *successCount != int32(len(mapDomains)) {
results <- Result{ErrorLevel, errors.New("failed to deliver to some recipients"), "", fields}
}
close(results)
}()
return results
}