From a18b9690e6dd4815c2fa7a869a34f302b1c7b92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20M=C3=BCller?= Date: Tue, 14 Apr 2020 10:45:30 +0200 Subject: [PATCH] Increase consistency at handling domain literals --- validate_email/email_address.py | 14 +++++++++++++- validate_email/mx_check.py | 7 +++++-- validate_email/regex_check.py | 24 ++++++++++++------------ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/validate_email/email_address.py b/validate_email/email_address.py index 52e768f..3e32a4f 100644 --- a/validate_email/email_address.py +++ b/validate_email/email_address.py @@ -1,3 +1,5 @@ +from typing import Optional + from idna.core import IDNAError, encode from .exceptions import AddressFormatError @@ -22,7 +24,7 @@ class EmailAddress(object): raise AddressFormatError # 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 else: try: @@ -46,6 +48,16 @@ class EmailAddress(object): """ 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 def ace(self) -> str: 'The ASCII-compatible encoding for the email address.' diff --git a/validate_email/mx_check.py b/validate_email/mx_check.py index 3e99c6f..b0242c4 100644 --- a/validate_email/mx_check.py +++ b/validate_email/mx_check.py @@ -109,8 +109,11 @@ def mx_check( """ host = helo_host or gethostname() from_address = from_address or email_address - mx_records = _get_mx_records( - domain=email_address.domain, timeout=dns_timeout) + if email_address.domain_literal_ip: + mx_records = [email_address.domain_literal_ip] + else: + mx_records = _get_mx_records( + domain=email_address.domain, timeout=dns_timeout) return _check_mx_records( mx_records=mx_records, smtp_timeout=smtp_timeout, helo_host=host, from_address=from_address, email_address=email_address) diff --git a/validate_email/regex_check.py b/validate_email/regex_check.py index eb4335a..b12d6fb 100644 --- a/validate_email/regex_check.py +++ b/validate_email/regex_check.py @@ -35,16 +35,16 @@ def regex_check(address: EmailAddress) -> bool: if not USER_REGEX.match(address.user): raise AddressFormatError - # Validate domain part: a) hostname. - if HOST_REGEX.match(address.ace_domain): - return True + # Validate domain part. + if address.domain_literal_ip: + 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. - literal_match = LITERAL_REGEX.match(address.ace_domain) - if literal_match: - ip_address = literal_match.group(1) - if _validate_ipv46_address(ip_address): - return True - - # Domain part not successfully validated. - raise AddressFormatError + # All validations successful. + return True -- 2.47.1