in quickstart, check outgoing smtp connectivity by dialing gmail.com mx host

if connection cannot be made, warn about it and point to configuring a
smarthost and the config options.

suggested by arnt & friend
This commit is contained in:
Mechiel Lukkien 2024-03-27 09:35:16 +01:00
parent d4958732c8
commit 0262f4621e
No known key found for this signature in database
4 changed files with 48 additions and 6 deletions

6
doc.go
View file

@ -20,7 +20,7 @@ any parameters. Followed by the help and usage information for each command.
mox [-config config/mox.conf] [-pedantic] ...
mox serve
mox quickstart [-existing-webserver] [-hostname host] user@domain [user | uid]
mox quickstart [-skipdial] [-existing-webserver] [-hostname host] user@domain [user | uid]
mox stop
mox setaccountpassword account
mox setadminpassword
@ -146,11 +146,13 @@ traffic to your existing backend applications. Look for "WebHandlers:" in the
output of "mox config describe-domains" and see the output of "mox example
webhandlers".
usage: mox quickstart [-existing-webserver] [-hostname host] user@domain [user | uid]
usage: mox quickstart [-skipdial] [-existing-webserver] [-hostname host] user@domain [user | uid]
-existing-webserver
use if a webserver is already running, so mox won't listen on port 80 and 443; you'll have to provide tls certificates/keys, and configure the existing webserver as reverse proxy, forwarding requests to mox.
-hostname string
hostname mox will run on, by default the hostname of the machine quickstart runs on; if specified, the IPs for the hostname are configured for the public listener
-skipdial
skip check for outgoing smtp (port 25) connectivity
# mox stop

View file

@ -59,7 +59,7 @@ func pwgen() string {
}
func cmdQuickstart(c *cmd) {
c.params = "[-existing-webserver] [-hostname host] user@domain [user | uid]"
c.params = "[-skipdial] [-existing-webserver] [-hostname host] user@domain [user | uid]"
c.help = `Quickstart generates configuration files and prints instructions to quickly set up a mox instance.
Quickstart writes configuration files, prints initial admin and account
@ -95,8 +95,10 @@ webhandlers".
`
var existingWebserver bool
var hostname string
var skipDial bool
c.flag.BoolVar(&existingWebserver, "existing-webserver", false, "use if a webserver is already running, so mox won't listen on port 80 and 443; you'll have to provide tls certificates/keys, and configure the existing webserver as reverse proxy, forwarding requests to mox.")
c.flag.StringVar(&hostname, "hostname", "", "hostname mox will run on, by default the hostname of the machine quickstart runs on; if specified, the IPs for the hostname are configured for the public listener")
c.flag.BoolVar(&skipDial, "skipdial", false, "skip check for outgoing smtp (port 25) connectivity")
args := c.Parse()
if len(args) != 1 && len(args) != 2 {
c.Usage()
@ -529,6 +531,44 @@ messages over SMTP.
}
}
// Check outgoing SMTP connectivity.
if !skipDial {
fmt.Printf("Checking if outgoing smtp connections can be made by connecting to gmail.com mx on port 25...")
mxctx, mxcancel := context.WithTimeout(context.Background(), 5*time.Second)
mx, _, err := resolver.LookupMX(mxctx, "gmail.com.")
mxcancel()
if err == nil && len(mx) == 0 {
err = errors.New("no mx records")
}
var ok bool
if err != nil {
fmt.Printf("\n\nERROR: looking up gmail.com mx record: %s\n", err)
} else {
dialctx, dialcancel := context.WithTimeout(context.Background(), 10*time.Second)
d := net.Dialer{}
addr := net.JoinHostPort(mx[0].Host, "25")
conn, err := d.DialContext(dialctx, "tcp", addr)
dialcancel()
if err != nil {
fmt.Printf("\n\nERROR: connecting to %s: %s\n", addr, err)
} else {
conn.Close()
fmt.Printf(" OK\n")
ok = true
}
}
if !ok {
fmt.Printf(`
WARNING: Could not verify outgoing smtp connections can be made, outgoing
delivery may not be working. Many providers block outgoing smtp connections by
default, requiring an explicit request or a cooldown period before allowing
outgoing smtp connections. To send through a smarthost, configure a "Transport"
in mox.conf and use it in "Routes" in domains.conf. See "mox example transport".
`)
}
}
zones := []dns.Domain{
{ASCII: "sbl.spamhaus.org"},
{ASCII: "bl.spamcop.net"},
@ -538,7 +578,7 @@ messages over SMTP.
var listed bool
for _, zone := range zones {
for _, ip := range hostIPs {
dnsblctx, dnsblcancel := context.WithTimeout(resolveCtx, 5*time.Second)
dnsblctx, dnsblcancel := context.WithTimeout(context.Background(), 5*time.Second)
status, expl, err := dnsbl.Lookup(dnsblctx, c.log.Logger, resolver, zone, net.ParseIP(ip))
dnsblcancel()
if status == dnsbl.StatusPass {

View file

@ -7,7 +7,7 @@ apk add unbound curl
(rm -r /tmp/mox 2>/dev/null || exit 0) # clean slate
mkdir /tmp/mox
cd /tmp/mox
mox quickstart moxtest1@mox1.example "$MOX_UID" > output.txt
mox quickstart -skipdial moxtest1@mox1.example "$MOX_UID" > output.txt
cp config/mox.conf config/mox.conf.orig
sed -i -e 's/letsencrypt:/pebble:/g' -e 's/: letsencrypt/: pebble/g' -e 's,DirectoryURL: https://acme-v02.api.letsencrypt.org/directory,DirectoryURL: https://acmepebble.example:14000/dir,' -e 's/SMTP:$/SMTP:\n\t\t\tFirstTimeSenderDelay: 1s/' config/mox.conf

View file

@ -7,7 +7,7 @@ apk add unbound
(rm -r /tmp/mox 2>/dev/null || exit 0) # clean slate
mkdir /tmp/mox
cd /tmp/mox
mox quickstart moxtest2@mox2.example "$MOX_UID" > output.txt
mox quickstart -skipdial moxtest2@mox2.example "$MOX_UID" > output.txt
cp config/mox.conf config/mox.conf.orig
sed -i -e 's,ACME: .*$,KeyCerts:\n\t\t\t\t-\n\t\t\t\t\tCertFile: /integration/tls/moxmail2.pem\n\t\t\t\t\tKeyFile: /integration/tls/moxmail2-key.pem\n\t\t\t\t-\n\t\t\t\t\tCertFile: /integration/tls/mox2-autoconfig.pem\n\t\t\t\t\tKeyFile: /integration/tls/mox2-autoconfig-key.pem\n\t\t\t\t-\n\t\t\t\t\tCertFile: /integration/tls/mox2-mtasts.pem\n\t\t\t\t\tKeyFile: /integration/tls/mox2-mtasts-key.pem\n,' -e 's/SMTP:$/SMTP:\n\t\t\tFirstTimeSenderDelay: 1s/' config/mox.conf