mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-18 14:47:03 +00:00
courier: SMTP falls back to A when MX does not exist
Make the SMTP courier fall back to the A record when MX does not exist, as per standard behaviour. This is not implemented nicely, because Go's API does not give a clear signal if the answer was that there are no MX records or something else happens. For now, we implement it with a heuristic that should work pretty reliably, but it's definitely not very nice.
This commit is contained in:
@@ -23,10 +23,6 @@ var (
|
|||||||
smtpPort = flag.String("testing__outgoing_smtp_port", "25",
|
smtpPort = flag.String("testing__outgoing_smtp_port", "25",
|
||||||
"port to use for outgoing SMTP connections, ONLY FOR TESTING")
|
"port to use for outgoing SMTP connections, ONLY FOR TESTING")
|
||||||
|
|
||||||
// Bypass the MX lookup, for testing purposes.
|
|
||||||
bypassMX = flag.Bool("testing__bypass_mx_lookup", false,
|
|
||||||
"bypass MX lookup, ONLY FOR TESTING")
|
|
||||||
|
|
||||||
// Fake MX records, used for testing only.
|
// Fake MX records, used for testing only.
|
||||||
fakeMX = map[string]string{}
|
fakeMX = map[string]string{}
|
||||||
)
|
)
|
||||||
@@ -40,7 +36,6 @@ func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
|
|||||||
defer tr.Finish()
|
defer tr.Finish()
|
||||||
tr.LazyPrintf("%s -> %s", from, to)
|
tr.LazyPrintf("%s -> %s", from, to)
|
||||||
|
|
||||||
// TODO: Fall back to A if MX is not available.
|
|
||||||
mx, err := lookupMX(envelope.DomainOf(to))
|
mx, err := lookupMX(envelope.DomainOf(to))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Note this is considered a permanent error.
|
// Note this is considered a permanent error.
|
||||||
@@ -142,17 +137,29 @@ func lookupMX(domain string) (string, error) {
|
|||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if *bypassMX {
|
|
||||||
return domain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
mxs, err := net.LookupMX(domain)
|
mxs, err := net.LookupMX(domain)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if len(mxs) == 0 {
|
||||||
} else if len(mxs) == 0 {
|
|
||||||
glog.Infof("domain %q has no MX, falling back to A", domain)
|
glog.Infof("domain %q has no MX, falling back to A", domain)
|
||||||
return domain, nil
|
return domain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return mxs[0].Host, nil
|
return mxs[0].Host, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// There was an error. It could be that the domain has no MX, in which
|
||||||
|
// case we have to fall back to A, or a bigger problem.
|
||||||
|
// Unfortunately, go's API doesn't let us easily distinguish between them.
|
||||||
|
// For now, if the error is permanent, we assume it's because there was no
|
||||||
|
// MX and fall back, otherwise we return.
|
||||||
|
// TODO: Find a better way to do this.
|
||||||
|
dnsErr, ok := err.(*net.DNSError)
|
||||||
|
if !ok {
|
||||||
|
return "", err
|
||||||
|
} else if dnsErr.Temporary() {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permanent error, we assume MX does not exist and fall back to A.
|
||||||
|
return domain, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ add_user srv-chasquid someone secretpassword
|
|||||||
# Bypass MX lookup, so it can find srv-exim (via our host alias).
|
# Bypass MX lookup, so it can find srv-exim (via our host alias).
|
||||||
mkdir -p .logs
|
mkdir -p .logs
|
||||||
chasquid -v=2 --log_dir=.logs --config_dir=config \
|
chasquid -v=2 --log_dir=.logs --config_dir=config \
|
||||||
--testing__outgoing_smtp_port=2025 \
|
--testing__outgoing_smtp_port=2025 &
|
||||||
--testing__bypass_mx_lookup &
|
|
||||||
|
|
||||||
wait_until_ready 1025
|
wait_until_ready 1025
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user