Merge pull request #15 from reinhard-mueller/master
Increase consistency at handling domain literals
This commit is contained in:
commit
0dd9910eb2
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from idna.core import IDNAError, encode
|
from idna.core import IDNAError, encode
|
||||||
|
|
||||||
from .exceptions import AddressFormatError
|
from .exceptions import AddressFormatError
|
||||||
|
@ -22,7 +24,7 @@ class EmailAddress(object):
|
||||||
raise AddressFormatError
|
raise AddressFormatError
|
||||||
|
|
||||||
# Convert internationalized domain name into the ACE encoding
|
# Convert internationalized domain name into the ACE encoding
|
||||||
if self._domain.startswith('[') and self._domain.endswith(']'):
|
if self.domain_literal_ip:
|
||||||
self._ace_domain = self._domain
|
self._ace_domain = self._domain
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -46,6 +48,16 @@ class EmailAddress(object):
|
||||||
"""
|
"""
|
||||||
return self._domain
|
return self._domain
|
||||||
|
|
||||||
|
@property
|
||||||
|
def domain_literal_ip(self) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
If the domain part of the email address is a literal IP address
|
||||||
|
enclosed in brackets, that IP address (without the brakcets) is
|
||||||
|
returned. Otherwise, `None` is returned.
|
||||||
|
"""
|
||||||
|
if self._domain.startswith('[') and self._domain.endswith(']'):
|
||||||
|
return self._domain[1:-1]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ace(self) -> str:
|
def ace(self) -> str:
|
||||||
'The ASCII-compatible encoding for the email address.'
|
'The ASCII-compatible encoding for the email address.'
|
||||||
|
|
|
@ -109,8 +109,11 @@ def mx_check(
|
||||||
"""
|
"""
|
||||||
host = helo_host or gethostname()
|
host = helo_host or gethostname()
|
||||||
from_address = from_address or email_address
|
from_address = from_address or email_address
|
||||||
mx_records = _get_mx_records(
|
if email_address.domain_literal_ip:
|
||||||
domain=email_address.domain, timeout=dns_timeout)
|
mx_records = [email_address.domain_literal_ip]
|
||||||
|
else:
|
||||||
|
mx_records = _get_mx_records(
|
||||||
|
domain=email_address.domain, timeout=dns_timeout)
|
||||||
return _check_mx_records(
|
return _check_mx_records(
|
||||||
mx_records=mx_records, smtp_timeout=smtp_timeout, helo_host=host,
|
mx_records=mx_records, smtp_timeout=smtp_timeout, helo_host=host,
|
||||||
from_address=from_address, email_address=email_address)
|
from_address=from_address, email_address=email_address)
|
||||||
|
|
|
@ -35,16 +35,16 @@ def regex_check(address: EmailAddress) -> bool:
|
||||||
if not USER_REGEX.match(address.user):
|
if not USER_REGEX.match(address.user):
|
||||||
raise AddressFormatError
|
raise AddressFormatError
|
||||||
|
|
||||||
# Validate domain part: a) hostname.
|
# Validate domain part.
|
||||||
if HOST_REGEX.match(address.ace_domain):
|
if address.domain_literal_ip:
|
||||||
return True
|
literal_match = LITERAL_REGEX.match(address.ace_domain)
|
||||||
|
if literal_match is None:
|
||||||
|
raise AddressFormatError
|
||||||
|
if not _validate_ipv46_address(literal_match[1]):
|
||||||
|
raise AddressFormatError
|
||||||
|
else:
|
||||||
|
if HOST_REGEX.match(address.ace_domain) is None:
|
||||||
|
raise AddressFormatError
|
||||||
|
|
||||||
# Validate domain part: b) literal IP address.
|
# All validations successful.
|
||||||
literal_match = LITERAL_REGEX.match(address.ace_domain)
|
return True
|
||||||
if literal_match:
|
|
||||||
ip_address = literal_match.group(1)
|
|
||||||
if _validate_ipv46_address(ip_address):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Domain part not successfully validated.
|
|
||||||
raise AddressFormatError
|
|
||||||
|
|
Loading…
Reference in New Issue