Skip to content

Commit 3b1b45c

Browse files
committed
Check that fallback A/AAAA records are globally reachable IP addresses, fixes #134
1 parent 8ec4239 commit 3b1b45c

File tree

4 files changed

+55
-1
lines changed

4 files changed

+55
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
In Development
22
--------------
33

4+
* When a domain name has no MX record but does have an A or AAAA record, if none of the IP addresses in the response are globally reachable (i.e. not Private-Use, Loopback, etc.), the response is treated as if there was no A/AAAA response and the email address will fail the deliverability check.
45
* When a domain name has no MX record but does have an A or AAAA record, the mx field in the object returned by validate_email incorrectly held the IP addresses rather than the domain itself.
56
* Fixes in tests.
67

email_validator/deliverability.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from typing import Optional, Any, Dict
22

3+
import ipaddress
4+
35
from .exceptions_types import EmailUndeliverableError
46

57
import dns.resolver
@@ -57,9 +59,29 @@ def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Option
5759
deliverability_info["mx_fallback_type"] = None
5860

5961
except dns.resolver.NoAnswer:
60-
# If there was no MX record, fall back to an A record. (RFC 5321 Section 5)
62+
# If there was no MX record, fall back to an A or AAA record
63+
# (RFC 5321 Section 5). Check A first since it's more common.
64+
65+
# If the A/AAAA response has no Globally Reachable IP address,
66+
# treat the response as if it were NoAnswer, i.e., the following
67+
# address types are not allowed fallbacks: Private-Use, Loopback,
68+
# Link-Local, and some other obscure ranges. See
69+
# https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
70+
# https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
71+
# (Issue #134.)
72+
def is_global_addr(ipaddr):
73+
try:
74+
ipaddr = ipaddress.ip_address(ipaddr)
75+
except ValueError:
76+
return False
77+
return ipaddr.is_global
78+
6179
try:
6280
response = dns_resolver.resolve(domain, "A")
81+
82+
if not any(is_global_addr(r.address) for r in response):
83+
raise dns.resolver.NoAnswer # fall back to AAAA
84+
6385
deliverability_info["mx"] = [(0, domain)]
6486
deliverability_info["mx_fallback_type"] = "A"
6587

@@ -69,6 +91,10 @@ def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Option
6991
# (It's unclear if SMTP servers actually do this.)
7092
try:
7193
response = dns_resolver.resolve(domain, "AAAA")
94+
95+
if not any(is_global_addr(r.address) for r in response):
96+
raise dns.resolver.NoAnswer
97+
7298
deliverability_info["mx"] = [(0, domain)]
7399
deliverability_info["mx_fallback_type"] = "AAAA"
74100

tests/mocked-dns-answers.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,32 @@
6060
"0 ."
6161
]
6262
},
63+
{
64+
"query": {
65+
"name": "g.mail.com",
66+
"type": "MX",
67+
"class": "IN"
68+
},
69+
"answer": []
70+
},
71+
{
72+
"query": {
73+
"name": "g.mail.com",
74+
"type": "A",
75+
"class": "IN"
76+
},
77+
"answer": []
78+
},
79+
{
80+
"query": {
81+
"name": "g.mail.com",
82+
"type": "AAAA",
83+
"class": "IN"
84+
},
85+
"answer": [
86+
"::1"
87+
]
88+
},
6389
{
6490
"query": {
6591
"name": "nellis.af.mil",

tests/test_deliverability.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def test_deliverability_found(domain, expected_response):
2727
[
2828
('xkxufoekjvjfjeodlfmdfjcu.com', 'The domain name {domain} does not exist'),
2929
('example.com', 'The domain name {domain} does not accept email'), # Null MX record
30+
('g.mail.com', 'The domain name {domain} does not accept email'), # No MX record but invalid AAAA record fallback (issue #134)
3031
('nellis.af.mil', 'The domain name {domain} does not send email'), # No MX record, A record fallback, reject-all SPF record.
3132
3233
# No MX or A/AAAA records, but some other DNS records must

0 commit comments

Comments
 (0)