diff --git a/email_validator/deliverability.py b/email_validator/deliverability.py index 4846091..95d73bc 100644 --- a/email_validator/deliverability.py +++ b/email_validator/deliverability.py @@ -72,12 +72,12 @@ def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Option deliverability_info["mx"] = [(0, str(r)) for r in response] deliverability_info["mx_fallback_type"] = "AAAA" - except dns.resolver.NoAnswer: + except dns.resolver.NoAnswer as e: # If there was no MX, A, or AAAA record, then mail to # this domain is not deliverable, although the domain # name has other records (otherwise NXDOMAIN would # have been raised). - raise EmailUndeliverableError(f"The domain name {domain_i18n} does not accept email.") + raise EmailUndeliverableError(f"The domain name {domain_i18n} does not accept email.") from e # Check for a SPF (RFC 7208) reject-all record ("v=spf1 -all") which indicates # no emails are sent from this domain (similar to a Null MX record @@ -96,10 +96,10 @@ def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Option # No TXT records means there is no SPF policy, so we cannot take any action. pass - except dns.resolver.NXDOMAIN: + except dns.resolver.NXDOMAIN as e: # The domain name does not exist --- there are no records of any sort # for the domain name. - raise EmailUndeliverableError(f"The domain name {domain_i18n} does not exist.") + raise EmailUndeliverableError(f"The domain name {domain_i18n} does not exist.") from e except dns.resolver.NoNameservers: # All nameservers failed to answer the query. This might be a problem @@ -122,6 +122,6 @@ def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Option # Unhandled conditions should not propagate. raise EmailUndeliverableError( "There was an error while checking if the domain name in the email address is deliverable: " + str(e) - ) + ) from e return deliverability_info diff --git a/email_validator/exceptions_types.py b/email_validator/exceptions_types.py index 88bbf05..4522b4f 100644 --- a/email_validator/exceptions_types.py +++ b/email_validator/exceptions_types.py @@ -80,7 +80,6 @@ def __getattr__(self, key): @property def email(self): - import warnings warnings.warn("ValidatedEmail.email is deprecated and will be removed, use ValidatedEmail.normalized instead", DeprecationWarning) return self.normalized diff --git a/email_validator/syntax.py b/email_validator/syntax.py index 3b5f204..6634ace 100644 --- a/email_validator/syntax.py +++ b/email_validator/syntax.py @@ -26,7 +26,6 @@ def split_email(email): # Since backslash-escaping is no longer needed because # the quotes are removed, remove backslash-escaping # to return in the normalized form. - import re local_part = re.sub(r"\\(.)", "\\1", local_part) return local_part, domain_part, True @@ -72,14 +71,14 @@ def validate_email_local_part(local: str, allow_smtputf8: bool = True, allow_emp if len(local) == 0: if not allow_empty_local: raise EmailSyntaxError("There must be something before the @-sign.") - else: - # The caller allows an empty local part. Useful for validating certain - # Postfix aliases. - return { - "local_part": local, - "ascii_local_part": local, - "smtputf8": False, - } + + # The caller allows an empty local part. Useful for validating certain + # Postfix aliases. + return { + "local_part": local, + "ascii_local_part": local, + "smtputf8": False, + } # Check the length of the local part by counting characters. # (RFC 5321 4.5.3.1.1) @@ -191,8 +190,8 @@ def validate_email_local_part(local: str, allow_smtputf8: bool = True, allow_emp # want to have an unhandled exception later. try: local.encode("utf8") - except ValueError: - raise EmailSyntaxError("The email address contains an invalid character.") + except ValueError as e: + raise EmailSyntaxError("The email address contains an invalid character.") from e # If this address passes only by the quoted string form, re-quote it # and backslash-escape quotes and backslashes (removing any unnecessary @@ -330,7 +329,7 @@ def validate_email_domain_name(domain, test_environment=False, globally_delivera try: domain = idna.uts46_remap(domain, std3_rules=False, transitional=False) except idna.IDNAError as e: - raise EmailSyntaxError(f"The part after the @-sign contains invalid characters ({e}).") + raise EmailSyntaxError(f"The part after the @-sign contains invalid characters ({e}).") from e # The domain part is made up dot-separated "labels." Each label must # have at least one character and cannot start or end with dashes, which @@ -374,11 +373,11 @@ def validate_email_domain_name(domain, test_environment=False, globally_delivera # the length check is applied to a string that is different from the # one the user supplied. Also I'm not sure if the length check applies # to the internationalized form, the IDNA ASCII form, or even both! - raise EmailSyntaxError("The email address is too long after the @-sign.") + raise EmailSyntaxError("The email address is too long after the @-sign.") from e # Other errors seem to not be possible because the call to idna.uts46_remap # would have already raised them. - raise EmailSyntaxError(f"The part after the @-sign contains invalid characters ({e}).") + raise EmailSyntaxError(f"The part after the @-sign contains invalid characters ({e}).") from e # Check the syntax of the string returned by idna.encode. # It should never fail. @@ -440,7 +439,7 @@ def validate_email_domain_name(domain, test_environment=False, globally_delivera try: domain_i18n = idna.decode(ascii_domain.encode('ascii')) except idna.IDNAError as e: - raise EmailSyntaxError(f"The part after the @-sign is not valid IDNA ({e}).") + raise EmailSyntaxError(f"The part after the @-sign is not valid IDNA ({e}).") from e # Check for invalid characters after normalization. These # should never arise. See the similar checks above. @@ -518,7 +517,7 @@ def validate_email_domain_literal(domain_literal): try: addr = ipaddress.IPv4Address(domain_literal) except ValueError as e: - raise EmailSyntaxError(f"The address in brackets after the @-sign is not valid: It is not an IPv4 address ({e}) or is missing an address literal tag.") + raise EmailSyntaxError(f"The address in brackets after the @-sign is not valid: It is not an IPv4 address ({e}) or is missing an address literal tag.") from e # Return the IPv4Address object and the domain back unchanged. return { @@ -531,7 +530,7 @@ def validate_email_domain_literal(domain_literal): try: addr = ipaddress.IPv6Address(domain_literal[5:]) except ValueError as e: - raise EmailSyntaxError(f"The IPv6 address in brackets after the @-sign is not valid ({e}).") + raise EmailSyntaxError(f"The IPv6 address in brackets after the @-sign is not valid ({e}).") from e # Return the IPv6Address object and construct a normalized # domain literal. diff --git a/email_validator/validate_email.py b/email_validator/validate_email.py index d2791fe..d6051a9 100644 --- a/email_validator/validate_email.py +++ b/email_validator/validate_email.py @@ -49,8 +49,8 @@ def validate_email( if not isinstance(email, str): try: email = email.decode("ascii") - except ValueError: - raise EmailSyntaxError("The email address is not valid ASCII.") + except ValueError as e: + raise EmailSyntaxError("The email address is not valid ASCII.") from e # Split the address into the local part (before the @-sign) # and the domain part (after the @-sign). Normally, there