-
Notifications
You must be signed in to change notification settings - Fork 1
/
verifier.go
135 lines (116 loc) · 2.81 KB
/
verifier.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
package verifier
import (
"crypto/tls"
"fmt"
"github.com/txthinking/socks5"
"net"
"net/smtp"
"strings"
"time"
)
type VerifyOptions struct {
To string
ProxyType string
ProxyAddress string
ProxyPort int
ProxyUsername string
ProxyPassword string
toInfo mailAddressInfo
}
func (r *VerifyOptions) parse() bool {
s1 := strings.Split(r.To, "@")
if len(s1) < 2 {
return false
}
r.toInfo.Address = r.To
r.toInfo.Name = ""
r.toInfo.Username = s1[0]
r.toInfo.Domain = s1[1]
return true
}
func (r VerifyOptions) HasProxy() bool {
if r.ProxyType == "" {
return false
}
if r.ProxyAddress == "" || r.ProxyPort == 0 {
return false
}
return true
}
type mailAddressInfo struct {
Name string
Address string
Username string
Domain string
}
type VerifyResult struct {
ValidFormat bool
Deliverable bool
HostExists bool
CatchAll bool
Message string
}
var (
ResultEmpty = VerifyResult{Message: "error with unknown"}
ResultFormatInvalid = VerifyResult{Message: "email format invalid", CatchAll: true}
ResultHostInvalid = VerifyResult{Message: "host has no mx records", ValidFormat: true, CatchAll: true}
)
func checkMXRecord(domain string) bool {
mxs, err := net.LookupMX(domain)
if err != nil {
return false
}
if len(mxs) == 0 {
return false
}
return true
}
type Dialer func(network, address string) (net.Conn, error)
func VerifyNormal(options VerifyOptions) VerifyResult {
if !options.parse() {
return ResultFormatInvalid
}
d := net.Dialer{Timeout: 5 * time.Second}
return verifyWithDialer(d.Dial, options)
}
func verifyWithDialer(dialer Dialer, options VerifyOptions) VerifyResult {
result := VerifyResult{}
result.ValidFormat = true
if !checkMXRecord(options.toInfo.Domain) {
return ResultHostInvalid
} else {
result.HostExists = true
}
smtpDomain := fmt.Sprintf("smtp.%s", options.toInfo.Domain)
conn, err := dialer("tcp", fmt.Sprintf("%s:%d", smtpDomain, 587))
if err != nil {
return VerifyResult{Message: err.Error()}
}
s, err := smtp.NewClient(conn, options.toInfo.Domain)
if err != nil {
return VerifyResult{Message: err.Error()}
}
err = s.StartTLS(&tls.Config{ServerName: smtpDomain})
if err != nil {
return VerifyResult{Message: err.Error()}
}
result.Deliverable = true
result.CatchAll = true
return result
}
func VerifyWithSocks5(options VerifyOptions) VerifyResult {
if !options.parse() {
return ResultFormatInvalid
}
socks, err := socks5.NewClient(fmt.Sprintf("%s:%d", options.ProxyAddress, options.ProxyPort), options.ProxyPassword, options.ProxyPassword, 5, 5)
if err != nil {
return VerifyResult{Message: err.Error()}
}
return verifyWithDialer(socks.Dial, options)
}
func Verify(options VerifyOptions) VerifyResult {
if options.HasProxy() {
return VerifyWithSocks5(options)
}
return VerifyNormal(options)
}