-
-
Notifications
You must be signed in to change notification settings - Fork 34
/
main.go
115 lines (108 loc) · 3.15 KB
/
main.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
package main
import (
"errors"
"flag"
"fmt"
"os"
"regexp"
"strings"
"github.com/blueimp/aws-smtp-relay/internal/auth"
"github.com/blueimp/aws-smtp-relay/internal/relay"
pinpointrelay "github.com/blueimp/aws-smtp-relay/internal/relay/pinpoint"
sesrelay "github.com/blueimp/aws-smtp-relay/internal/relay/ses"
"github.com/mhale/smtpd"
)
var (
addr = flag.String("a", ":1025", "TCP listen address")
name = flag.String("n", "AWS SMTP Relay", "SMTP service name")
host = flag.String("h", "", "Server hostname")
certFile = flag.String("c", "", "TLS cert file")
keyFile = flag.String("k", "", "TLS key file")
startTLS = flag.Bool("s", false, "Require TLS via STARTTLS extension")
onlyTLS = flag.Bool("t", false, "Listen for incoming TLS connections only")
relayAPI = flag.String("r", "ses", "Relay API to use (ses|pinpoint)")
setName = flag.String("e", "", "Amazon SES Configuration Set Name")
ips = flag.String("i", "", "Allowed client IPs (comma-separated)")
user = flag.String("u", "", "Authentication username")
allowFrom = flag.String("l", "", "Allowed sender emails regular expression")
denyTo = flag.String("d", "", "Denied recipient emails regular expression")
)
var ipMap map[string]bool
var bcryptHash []byte
var password []byte
var relayClient relay.Client
func server() (srv *smtpd.Server, err error) {
authMechs := make(map[string]bool)
if *user != "" && len(bcryptHash) > 0 && len(password) == 0 {
authMechs["CRAM-MD5"] = false
}
srv = &smtpd.Server{
Addr: *addr,
Handler: relayClient.Send,
Appname: *name,
Hostname: *host,
TLSRequired: *startTLS,
TLSListener: *onlyTLS,
AuthRequired: ipMap != nil || *user != "",
AuthHandler: auth.New(ipMap, *user, bcryptHash, password).Handler,
AuthMechs: authMechs,
}
if *certFile != "" && *keyFile != "" {
keyPass := os.Getenv("TLS_KEY_PASS")
if keyPass != "" {
err = srv.ConfigureTLSWithPassphrase(*certFile, *keyFile, keyPass)
} else {
err = srv.ConfigureTLS(*certFile, *keyFile)
}
}
return
}
func configure() error {
var allowFromRegExp *regexp.Regexp
var denyToRegExp *regexp.Regexp
var err error
if *allowFrom != "" {
allowFromRegExp, err = regexp.Compile(*allowFrom)
if err != nil {
return errors.New("Allowed sender emails: " + err.Error())
}
}
if *denyTo != "" {
denyToRegExp, err = regexp.Compile(*denyTo)
if err != nil {
return errors.New("Denied recipient emails: " + err.Error())
}
}
switch *relayAPI {
case "pinpoint":
relayClient = pinpointrelay.New(setName, allowFromRegExp, denyToRegExp)
case "ses":
relayClient = sesrelay.New(setName, allowFromRegExp, denyToRegExp)
default:
return errors.New("Invalid relay API: " + *relayAPI)
}
if *ips != "" {
ipMap = make(map[string]bool)
for _, ip := range strings.Split(*ips, ",") {
ipMap[ip] = true
}
}
bcryptHash = []byte(os.Getenv("BCRYPT_HASH"))
password = []byte(os.Getenv("PASSWORD"))
return nil
}
func main() {
flag.Parse()
var srv *smtpd.Server
err := configure()
if err == nil {
srv, err = server()
if err == nil {
err = srv.ListenAndServe()
}
}
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}