From a248d9ad198dae63d0cbfa20cd7c2ce51c8db45a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20K=C3=A1rolyi?= Date: Tue, 16 Nov 2021 23:38:37 +0100 Subject: [PATCH] Migrating to gitea part 1 --- {.github => .gitea}/FUNDING.yml | 0 .../ISSUE_TEMPLATE/bug_report.md | 2 +- {.github => .gitea}/stale.yml | 0 .gitignore | 3 + CHANGELOG.txt | 8 +- README.md | 182 ++++++++++++++++ README.rst | 194 ------------------ setup.py | 16 +- validate_email/dns_check.py | 6 +- validate_email/smtp_check.py | 16 +- validate_email/updater.py | 2 +- validate_email/validate_email.py | 22 +- 12 files changed, 225 insertions(+), 226 deletions(-) rename {.github => .gitea}/FUNDING.yml (100%) rename {.github => .gitea}/ISSUE_TEMPLATE/bug_report.md (87%) rename {.github => .gitea}/stale.yml (100%) create mode 100644 README.md delete mode 100644 README.rst diff --git a/.github/FUNDING.yml b/.gitea/FUNDING.yml similarity index 100% rename from .github/FUNDING.yml rename to .gitea/FUNDING.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.gitea/ISSUE_TEMPLATE/bug_report.md similarity index 87% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .gitea/ISSUE_TEMPLATE/bug_report.md index bbc01b6..41ad1f9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.gitea/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- -- [ ] I have read and understood the [FAQ](https://github.com/karolyi/py3-validate-email/blob/master/FAQ.md) +- [ ] I have read and understood the [FAQ](https://gitea.ksol.io/karolyi/py3-validate-email/src/branch/master/FAQ.md) **Describe the bug** diff --git a/.github/stale.yml b/.gitea/stale.yml similarity index 100% rename from .github/stale.yml rename to .gitea/stale.yml diff --git a/.gitignore b/.gitignore index 0d83730..916c814 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ dist MANIFEST *.egg-info venv +.eggs +pyrightconfig.json +__pycache__ diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4c378bc..c3558ee 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,5 @@ 1.0.2: -- Handle an SSLError during STARTTLS correctly (See https://github.com/karolyi/py3-validate-email/issues/79) +- Handle an SSLError during STARTTLS correctly (See https://gitea.ksol.io/karolyi/py3-validate-email/issues/79) - Extend options with an `smtp_skip_tls` option. When `True`, the module won't initiate a TLS session. Defaults to `False`. - Extend options with a `smtp_tls_context` option. When passed and `smtp_skip_tls` is `False` (or not passed), the client will use the passed `SSLContext`. - Typo fix: 'ambigious' -> 'ambiguous' @@ -30,13 +30,13 @@ - Props to @reinhard-mueller for coming up with the new proposals and helping in refining the idea. 0.2.16: -- Workaround for a bug in the built-in python 3.8 smtp library: https://github.com/karolyi/py3-validate-email/issues/50 +- Workaround for a bug in the built-in python 3.8 smtp library: https://gitea.ksol.io/karolyi/py3-validate-email/issues/50 0.2.15: - Added a `skip_smtp` option to optionally skip the SMTP protocol check after the DNS level checks, by @SergeyKons 0.2.14: -- More improvements, courtesy of Reinhard Müller: https://github.com/karolyi/py3-validate-email/pull/48 +- More improvements, courtesy of Reinhard Müller: https://gitea.ksol.io/karolyi/py3-validate-email/pulls/48 0.2.13: - Fix 5xx errors not getting through in the exception parameters on the RCPT TO @@ -81,7 +81,7 @@ - Fixed built-in datadir creation again. 0.2.3: -- Fixed https://github.com/karolyi/py3-validate-email/issues/13 +- Fixed https://gitea.ksol.io/karolyi/py3-validate-email/issues/13 0.2.2: - Fixed the automatic download of the validate_email/data directory on diff --git a/README.md b/README.md new file mode 100644 index 0000000..2ce41e3 --- /dev/null +++ b/README.md @@ -0,0 +1,182 @@ +![image](https://app.travis-ci.com/karolyi/py3-validate-email.svg?branch=master%0A%20:target:%20https://app.travis-ci.com/karolyi/py3-validate-email) + +![image](https://bmc-cdn.nyc3.digitaloceanspaces.com/BMC-button-images/custom_images/orange_img.png%0A%20:target:%20https://buymeacoff.ee/karolyi) + +py3-validate-email +================== + +py3-validate-email is a package for Python that check if an email is valid, not blacklisted, properly formatted and really exists. + +This module is for Python 3.6 and above! + +INSTALLATION +------------ + +You can install the package with pip: + + python -m pip install py3-validate-email + +USAGE +----- + +Basic usage: + + from validate_email import validate_email + is_valid = validate_email( + email_address='example@example.com', + check_format=True, + check_blacklist=True, + check_dns=True, + dns_timeout=10, + check_smtp=True, + smtp_timeout=10, + smtp_helo_host='my.host.name', + smtp_from_address='my@from.addr.ess', + smtp_skip_tls=False, + smtp_tls_context=None, + smtp_debug=False) + +### Parameters + +email\_address: the email address to check + +check\_format: check whether the email address has a valid structure; defaults to True + +check\_blacklist: check the email against the blacklist of domains downloaded from ; defaults to True + +check\_dns: check the DNS mx-records, defaults to True + +dns\_timeout: seconds until DNS timeout; defaults to 10 seconds + +check\_smtp: check whether the email actually exists by initiating an SMTP conversation; defaults to True + +smtp\_timeout: seconds until SMTP timeout; defaults to 10 seconds + +smtp\_helo\_host: the hostname to use in SMTP HELO/EHLO; if set to None (the default), the fully qualified domain name of the local host is used + +smtp\_from\_address: the email address used for the sender in the SMTP conversation; if set to None (the default), the email\_address parameter is used as the sender as well + +smtp\_skip\_tls: skip the TLS negotiation with the server, even when available. defaults to False + +smtp\_tls\_context: an SSLContext to use with the TLS negotiation when the server supports it. defaults to None + +smtp\_debug: activate smtplib's debug output which always goes to stderr; defaults to False + +### Result + +The function validate\_email() returns the following results: + +True +All requested checks were successful for the given email address. + +False +At least one of the requested checks failed for the given email address. + +None +None of the requested checks failed, but at least one of them yielded an ambiguous result. Currently, the SMTP check is the only check which can actually yield an ambiguous result. + +### Getting more information + +The function validate\_email\_or\_fail() works exactly like validate\_email, except that it raises an exception in the case of validation failure and ambiguous result instead of returning False or None, respectively. + +All these exceptions descend from EmailValidationError. Please see below for the exact exceptions raised by the various checks. Note that all exception classes are defined in the module validate\_email.exceptions. + +Please note that SMTPTemporaryError indicates an ambiguous check result rather than a check failure, so if you use validate\_email\_or\_fail(), you probably want to catch this exception. + +The checks +---------- + +By default, all checks are enabled, but each of them can be disabled by one of the check\_... parameters. Note that, however, check\_smtp implies check\_dns. + +### check\_format + +Check whether the given email address conforms to the general format requirements of valid email addresses. + +validate\_email\_or\_fail() raises AddressFormatError on any failure of this test. + +### check\_blacklist + +Check whether the domain part of the given email address (the part behind the ["@"](mailto:"@")) is known as a disposable and temporary email address domain. These are often used to register dummy users in order to spam or abuse some services. + +A list of such domains is maintained at , and this module uses that list. + +validate\_email\_or\_fail() raises DomainBlacklistedError if the email address belongs to a blacklisted domain. + +### check\_dns + +Check whether there is a valid list of servers responsible for delivering emails to the given email address. + +First, a DNS query is issued for the email address' domain to retrieve a list of all MX records. That list is then stripped of duplicates and malformatted entries. If at the end of this procedure, at least one valid MX record remains, the check is considered successful. + +On failure of this check, validate\_email\_or\_fail() raises one of the following exceptions, all of which descend from DNSError: + +DomainNotFoundError +The domain of the email address cannot be found at all. + +NoNameserverError +There is no nameserver for the domain. + +DNSTimeoutError +A timeout occured when querying the nameserver. Note that the timeout period can be changed with the dns\_timeout parameter. + +DNSConfigurationError +The nameserver is misconfigured. + +NoMXError +The nameserver does not list any MX records for the domain. + +NoValidMXError +The nameserver lists MX records for the domain, but none of them is valid. + +### check\_smtp + +Check whether the given email address exists by simulating an actual email delivery. + +A connection to the SMTP server identified through the domain's MX record is established, and an SMTP conversation is initiated up to the point where the server confirms the existence of the email address. After that, instead of actually sending an email, the conversation is cancelled. + +Unless you set smtp\_skip\_tls to True, the module will try to negotiate a TLS connection with STARTTLS, and silently fall back to an unencrypted SMTP connection if the server doesn't support it. Additionally, depending on your client configuration, the TLS negotiation might fail which will result in an ambiguous response for the given host as the module will be unable to communicate with the host after the negotiation fails. In trying to succeed, you can pass an SSLContext as an smtp\_tls\_context parameter, but remember that the server might still deny the negotiation based on how you set the SSLContext up, and based on its security settings as well. + +If the SMTP server replies to the RCPT TO command with a code 250 (success) response, the check is considered successful. + +If the SMTP server replies with a code 5xx (permanent error) response at any point in the conversation, the check is considered failed. + +If the SMTP server cannot be connected, unexpectedly closes the connection, or replies with a code 4xx (temporary error) at any stage of the conversation, the check is considered ambiguous. + +If there is more than one valid MX record for the domain, they are tried in order of priority until the first time the check is either successful or failed. Only in case of an ambiguous check result, the next server is tried, and only if the check result is ambiguous for all servers, the overall check is considered ambiguous as well. + +On failure of this check or on ambiguous result, validate\_email\_or\_fail() raises one of the following exceptions, all of which descend from SMTPError: + +AddressNotDeliverableError +The SMTP server permanently refused the email address. Technically, this means that the server replied to the RCPT TO command with a code 5xx response. + +SMTPCommunicationError +The SMTP server refused to even let us get to the point where we could ask it about the email address. Technically, this means that the server sent a code 5xx response either immediately after connection, or as a reply to the EHLO (or HELO) or MAIL FROM commands. + +SMTPTemporaryError +A temporary error occured during the check for all available MX servers. This is considered an ambiguous check result. For example, greylisting is a frequent cause for this. Make sure you check the contents of the message. + +All of the above three exceptions provide further details about the error response(s) in the exception's instance variable error\_messages. + +Auto-updater +------------ + +The package contains an auto-updater for downloading and updating the built-in blacklist.txt. It will run on each module load (and installation), but will try to update the content only if the file is older than 5 days, and if the content is not the same that's already downloaded. + +The update can be triggered manually: + + from validate_email.updater import update_builtin_blacklist + + update_builtin_blacklist( + force: bool = False, + background: bool = True, + callback: Callable = None + ) -> Optional[Thread] + +force: forces the update even if the downloaded/installed file is fresh enough. + +background: starts the update in a `Thread` so it won't make your code hang while it's updating. If you set this to true, the function will return the Thread used for starting the update so you can `join()` it if necessary. + +callback: An optional Callable (function/method) to be called when the update is done. + +Read the [FAQ](https://gitea.ksol.io/karolyi/py3-validate-email/src/branch/master/FAQ.md)! +------------------------------------------------------------------------------------ diff --git a/README.rst b/README.rst deleted file mode 100644 index 13771b4..0000000 --- a/README.rst +++ /dev/null @@ -1,194 +0,0 @@ -.. image:: https://app.travis-ci.com/karolyi/py3-validate-email.svg?branch=master - :target: https://app.travis-ci.com/karolyi/py3-validate-email -.. image:: https://bmc-cdn.nyc3.digitaloceanspaces.com/BMC-button-images/custom_images/orange_img.png - :target: https://buymeacoff.ee/karolyi - -============================ -py3-validate-email -============================ - -py3-validate-email is a package for Python that check if an email is valid, not blacklisted, properly formatted and really exists. - -This module is for Python 3.6 and above! - -INSTALLATION -============================ - -You can install the package with pip:: - - python -m pip install py3-validate-email - - -USAGE -============================ - -Basic usage:: - - from validate_email import validate_email - is_valid = validate_email( - email_address='example@example.com', - check_format=True, - check_blacklist=True, - check_dns=True, - dns_timeout=10, - check_smtp=True, - smtp_timeout=10, - smtp_helo_host='my.host.name', - smtp_from_address='my@from.addr.ess', - smtp_skip_tls=False, - smtp_tls_context=None, - smtp_debug=False) - -Parameters ----------------------------- - -:code:`email_address`: the email address to check - -:code:`check_format`: check whether the email address has a valid structure; defaults to :code:`True` - -:code:`check_blacklist`: check the email against the blacklist of domains downloaded from https://github.com/disposable-email-domains/disposable-email-domains; defaults to :code:`True` - -:code:`check_dns`: check the DNS mx-records, defaults to :code:`True` - -:code:`dns_timeout`: seconds until DNS timeout; defaults to 10 seconds - -:code:`check_smtp`: check whether the email actually exists by initiating an SMTP conversation; defaults to :code:`True` - -:code:`smtp_timeout`: seconds until SMTP timeout; defaults to 10 seconds - -:code:`smtp_helo_host`: the hostname to use in SMTP HELO/EHLO; if set to :code:`None` (the default), the fully qualified domain name of the local host is used - -:code:`smtp_from_address`: the email address used for the sender in the SMTP conversation; if set to :code:`None` (the default), the :code:`email_address` parameter is used as the sender as well - -:code:`smtp_skip_tls`: skip the TLS negotiation with the server, even when available. defaults to :code:`False` - -:code:`smtp_tls_context`: an :code:`SSLContext` to use with the TLS negotiation when the server supports it. defaults to :code:`None` - -:code:`smtp_debug`: activate :code:`smtplib`'s debug output which always goes to stderr; defaults to :code:`False` - -Result ----------------------------- - -The function :code:`validate_email()` returns the following results: - -:code:`True` - All requested checks were successful for the given email address. - -:code:`False` - At least one of the requested checks failed for the given email address. - -:code:`None` - None of the requested checks failed, but at least one of them yielded an ambiguous result. Currently, the SMTP check is the only check which can actually yield an ambiguous result. - -Getting more information ----------------------------- - -The function :code:`validate_email_or_fail()` works exactly like :code:`validate_email`, except that it raises an exception in the case of validation failure and ambiguous result instead of returning :code:`False` or :code:`None`, respectively. - -All these exceptions descend from :code:`EmailValidationError`. Please see below for the exact exceptions raised by the various checks. Note that all exception classes are defined in the module :code:`validate_email.exceptions`. - -Please note that :code:`SMTPTemporaryError` indicates an ambiguous check result rather than a check failure, so if you use :code:`validate_email_or_fail()`, you probably want to catch this exception. - -The checks -============================ - -By default, all checks are enabled, but each of them can be disabled by one of the :code:`check_...` parameters. Note that, however, :code:`check_smtp` implies :code:`check_dns`. - -:code:`check_format` ----------------------------- - -Check whether the given email address conforms to the general format requirements of valid email addresses. - -:code:`validate_email_or_fail()` raises :code:`AddressFormatError` on any failure of this test. - -:code:`check_blacklist` ----------------------------- - -Check whether the domain part of the given email address (the part behind the "@") is known as a disposable and temporary email address domain. These are often used to register dummy users in order to spam or abuse some services. - -A list of such domains is maintained at https://github.com/disposable-email-domains/disposable-email-domains, and this module uses that list. - -:code:`validate_email_or_fail()` raises :code:`DomainBlacklistedError` if the email address belongs to a blacklisted domain. - -:code:`check_dns` ----------------------------- - -Check whether there is a valid list of servers responsible for delivering emails to the given email address. - -First, a DNS query is issued for the email address' domain to retrieve a list of all MX records. That list is then stripped of duplicates and malformatted entries. If at the end of this procedure, at least one valid MX record remains, the check is considered successful. - -On failure of this check, :code:`validate_email_or_fail()` raises one of the following exceptions, all of which descend from :code:`DNSError`: - -:code:`DomainNotFoundError` - The domain of the email address cannot be found at all. - -:code:`NoNameserverError` - There is no nameserver for the domain. - -:code:`DNSTimeoutError` - A timeout occured when querying the nameserver. Note that the timeout period can be changed with the :code:`dns_timeout` parameter. - -:code:`DNSConfigurationError` - The nameserver is misconfigured. - -:code:`NoMXError` - The nameserver does not list any MX records for the domain. - -:code:`NoValidMXError` - The nameserver lists MX records for the domain, but none of them is valid. - -:code:`check_smtp` ----------------------------- - -Check whether the given email address exists by simulating an actual email delivery. - -A connection to the SMTP server identified through the domain's MX record is established, and an SMTP conversation is initiated up to the point where the server confirms the existence of the email address. After that, instead of actually sending an email, the conversation is cancelled. - -Unless you set :code:`smtp_skip_tls` to :code:`True`, the module will try to negotiate a TLS connection with STARTTLS, and silently fall back to an unencrypted SMTP connection if the server doesn't support it. Additionally, depending on your client configuration, the TLS negotiation might fail which will result in an ambiguous response for the given host as the module will be unable to communicate with the host after the negotiation fails. In trying to succeed, you can pass an :code:`SSLContext` as an :code:`smtp_tls_context` parameter, but remember that the server might still deny the negotiation based on how you set the :code:`SSLContext` up, and based on its security settings as well. - -If the SMTP server replies to the :code:`RCPT TO` command with a code 250 (success) response, the check is considered successful. - -If the SMTP server replies with a code 5xx (permanent error) response at any point in the conversation, the check is considered failed. - -If the SMTP server cannot be connected, unexpectedly closes the connection, or replies with a code 4xx (temporary error) at any stage of the conversation, the check is considered ambiguous. - -If there is more than one valid MX record for the domain, they are tried in order of priority until the first time the check is either successful or failed. Only in case of an ambiguous check result, the next server is tried, and only if the check result is ambiguous for all servers, the overall check is considered ambiguous as well. - -On failure of this check or on ambiguous result, :code:`validate_email_or_fail()` raises one of the following exceptions, all of which descend from :code:`SMTPError`: - -:code:`AddressNotDeliverableError` - The SMTP server permanently refused the email address. Technically, this means that the server replied to the :code:`RCPT TO` command with a code 5xx response. - -:code:`SMTPCommunicationError` - The SMTP server refused to even let us get to the point where we could ask it about the email address. Technically, this means that the server sent a code 5xx response either immediately after connection, or as a reply to the :code:`EHLO` (or :code:`HELO`) or :code:`MAIL FROM` commands. - -:code:`SMTPTemporaryError` - A temporary error occured during the check for all available MX servers. This is considered an ambiguous check result. For example, greylisting is a frequent cause for this. Make sure you check the contents of the message. - -All of the above three exceptions provide further details about the error response(s) in the exception's instance variable :code:`error_messages`. - -Auto-updater -============================ - -The package contains an auto-updater for downloading and updating the built-in blacklist.txt. It will run on each module load (and installation), but will try to update the content only if the file is older than 5 days, and if the content is not the same that's already downloaded. - -The update can be triggered manually:: - - from validate_email.updater import update_builtin_blacklist - - update_builtin_blacklist( - force: bool = False, - background: bool = True, - callback: Callable = None - ) -> Optional[Thread] - -:code:`force`: forces the update even if the downloaded/installed file is fresh enough. - -:code:`background`: starts the update in a ``Thread`` so it won't make your code hang while it's updating. If you set this to true, the function will return the Thread used for starting the update so you can ``join()`` it if necessary. - -:code:`callback`: An optional `Callable` (function/method) to be called when the update is done. - -Read the FAQ_! -============================ - -.. _FAQ: https://github.com/karolyi/py3-validate-email/blob/master/FAQ.md diff --git a/setup.py b/setup.py index 12b7745..0284efb 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,8 @@ def run_initial_updater(path: Path): orig_dont_write_bytecode = sys.dont_write_bytecode sys.dont_write_bytecode = True try: - from updater import BLACKLIST_FILEPATH_INSTALLED, BlacklistUpdater + from updater import ( # type: ignore + BLACKLIST_FILEPATH_INSTALLED, BlacklistUpdater) log.info(f'downloading blacklist to {BLACKLIST_FILEPATH_INSTALLED}') BlacklistUpdater()._install() finally: @@ -34,8 +35,8 @@ class DevelopCommand(develop): def run(self): super().run() - if not self.dry_run: - run_initial_updater(Path(__file__).parent) + if not self.dry_run: # type: ignore + run_initial_updater(path=Path(__file__).parent) class BuildPyCommand(build_py): @@ -63,9 +64,10 @@ setup( author_email='laszlo@karolyi.hu', description=( 'Email validator with regex, blacklisted domains and SMTP checking.'), - long_description=Path(__file__).parent.joinpath('README.rst').read_text(), - long_description_content_type='text/x-rst', + long_description=Path(__file__).parent.joinpath('README.md').read_text(), + long_description_content_type='text/markdown', keywords='email validation verification mx verify', - url='http://github.com/karolyi/py3-validate-email', - cmdclass=dict(build_py=BuildPyCommand, develop=DevelopCommand), + url='http://gitea.ksol.io/karolyi/py3-validate-email', + cmdclass=dict( + build_py=BuildPyCommand, develop=DevelopCommand), # type: ignore license='LGPL') diff --git a/validate_email/dns_check.py b/validate_email/dns_check.py index 2170500..6cd046d 100644 --- a/validate_email/dns_check.py +++ b/validate_email/dns_check.py @@ -11,7 +11,7 @@ from .exceptions import ( NoNameserverError, NoValidMXError) -def _get_mx_records(domain: str, timeout: int) -> Answer: +def _get_mx_records(domain: str, timeout: float) -> Answer: 'Return the DNS response for checking, optionally raise exceptions.' try: return resolve( @@ -29,7 +29,7 @@ def _get_mx_records(domain: str, timeout: int) -> Answer: raise NoMXError -def _get_cleaned_mx_records(domain: str, timeout: int) -> list: +def _get_cleaned_mx_records(domain: str, timeout: float) -> list: """ Return a list of hostnames in the MX record, raise an exception on any issues. @@ -49,7 +49,7 @@ def _get_cleaned_mx_records(domain: str, timeout: int) -> list: return result -def dns_check(email_address: EmailAddress, timeout: int = 10) -> list: +def dns_check(email_address: EmailAddress, timeout: float = 10) -> list: """ Check whether there are any responsible SMTP servers for the email address by looking up the DNS MX records. diff --git a/validate_email/smtp_check.py b/validate_email/smtp_check.py index 5a6a80c..ffe250f 100644 --- a/validate_email/smtp_check.py +++ b/validate_email/smtp_check.py @@ -28,7 +28,7 @@ class _SMTPChecker(SMTP): """ def __init__( - self, local_hostname: str, timeout: float, debug: bool, + self, local_hostname: Optional[str], timeout: float, debug: bool, sender: EmailAddress, recip: EmailAddress, skip_tls: bool = False, tls_context: SSLContext = None): """ @@ -66,14 +66,17 @@ class _SMTPChecker(SMTP): """ self.__command = 'connect' # Used for error messages. self._host = host # Workaround: Missing in standard smtplib! + # Use an OS assigned source port if source_address is passed + _source_address = None if source_address is None \ + else (source_address, 0) try: code, message = super().connect( - host=host, port=port, source_address=source_address) + host=host, port=port, source_address=_source_address) except OSError as error: raise SMTPServerDisconnected(str(error)) if code >= 400: raise SMTPResponseException(code=code, msg=message) - return code, message + return code, message.decode() def starttls(self, *args, **kwargs): """ @@ -134,9 +137,11 @@ class _SMTPChecker(SMTP): def _handle_smtpresponseexception( self, exc: SMTPResponseException) -> bool: 'Handle an `SMTPResponseException`.' + smtp_error = exc.smtp_error.decode(errors='ignore') \ + if type(exc.smtp_error) is bytes else exc.smtp_error smtp_message = SMTPMessage( command=self.__command, code=exc.smtp_code, - text=exc.smtp_error.decode(errors='ignore'), exceptions=(exc,)) + text=smtp_error, exceptions=(exc,)) if exc.smtp_code >= 500: raise SMTPCommunicationError( error_messages={self._host: smtp_message}) @@ -161,7 +166,7 @@ class _SMTPChecker(SMTP): self.starttls(context=self.__tls_context) self.ehlo_or_helo_if_needed() self.mail(sender=self.__sender.ace) - code, message = self.rcpt(recip=self.__recip.ace) + code, _ = self.rcpt(recip=self.__recip.ace) except SMTPServerDisconnected as exc: self.__temporary_errors[self._host] = SMTPMessage( command=self.__command, code=451, text=str(exc), @@ -190,6 +195,7 @@ class _SMTPChecker(SMTP): # Raise exception for collected temporary errors if self.__temporary_errors: raise SMTPTemporaryError(error_messages=self.__temporary_errors) + return False def smtp_check( diff --git a/validate_email/updater.py b/validate_email/updater.py index c258bb9..ba9e3ba 100644 --- a/validate_email/updater.py +++ b/validate_email/updater.py @@ -75,7 +75,7 @@ class BlacklistUpdater(object): 'Downlad and store blacklist file.' LOGGER.debug(msg=f'Checking {BLACKLIST_URL}') request = Request(url=BLACKLIST_URL, headers=headers) - response = urlopen(url=request) # type: HTTPResponse + response: HTTPResponse = urlopen(url=request) # New data available LOGGER.debug(msg=f'Writing response into {blacklist_path}') blacklist_path.write_bytes(response.fp.read()) diff --git a/validate_email/validate_email.py b/validate_email/validate_email.py index e3e88c1..8195723 100644 --- a/validate_email/validate_email.py +++ b/validate_email/validate_email.py @@ -41,25 +41,25 @@ def validate_email_or_fail( if the validation result is ambiguous, and raise an exception if the validation fails. """ - email_address = EmailAddress(address=email_address) + email_address_to = EmailAddress(address=email_address) if check_format: - regex_check(email_address=email_address) + regex_check(email_address=email_address_to) if check_blacklist: - domainlist_check(email_address=email_address) + domainlist_check(email_address=email_address_to) if not check_dns and not check_smtp: # check_smtp implies check_dns. return True - mx_records = dns_check(email_address=email_address, timeout=dns_timeout) + mx_records = dns_check(email_address=email_address_to, timeout=dns_timeout) if not check_smtp: return True - if smtp_from_address is not None: - try: - smtp_from_address = EmailAddress(address=smtp_from_address) - except AddressFormatError: - raise FromAddressFormatError + try: + email_address_from = None if not smtp_from_address else \ + EmailAddress(address=smtp_from_address) + except AddressFormatError: + raise FromAddressFormatError return smtp_check( - email_address=email_address, mx_records=mx_records, + email_address=email_address_to, mx_records=mx_records, timeout=smtp_timeout, helo_host=smtp_helo_host, - from_address=smtp_from_address, skip_tls=smtp_skip_tls, + from_address=email_address_from, skip_tls=smtp_skip_tls, tls_context=smtp_tls_context, debug=smtp_debug)