diff --git a/.bumpversion.cfg b/.bumpversion.cfg index ac5ef580..d9aab0b8 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.12.3 +current_version = 0.12.4 commit = False tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(-(?P[a-z]+)(?P\d+))? diff --git a/coverage.xml b/coverage.xml index 65830067..d2c9fc91 100644 --- a/coverage.xml +++ b/coverage.xml @@ -1,5 +1,5 @@ - + diff --git a/docs/recipes/emailValidation.md b/docs/recipes/emailValidation.md new file mode 100644 index 00000000..12d0fb54 --- /dev/null +++ b/docs/recipes/emailValidation.md @@ -0,0 +1,99 @@ +# Validating Email Addresses +Example of how to use in a script + +```python + +from dsg_lib.common_functions.email_validation import validate_email_address + +import pprint +import time + + +if __name__ == "__main__": + + # create a list of email addresses to check if valid + email_addresses = [ + "bob@devsetgo.com", + "bob@devset.go", + "foo@yahoo.com", + "bob@gmail.com", + "very fake@devsetgo.com", + "jane.doe@example.com", + "john_doe@example.co.uk", + "user.name+tag+sorting@example.com", + "x@example.com", # shortest possible email address + "example-indeed@strange-example.com", + "admin@mailserver1", # local domain name with no TLD + "example@s.example", # see the list of Internet top-level domains + '" "@example.org', # space between the quotes + '"john..doe"@example.org', # quoted double dot + "mailhost!username@example.org", # bangified host route used for uucp mailers + "user%example.com@example.org", # percent sign in local part + "user-@example.org", # valid due to the last character being an allowed character + # Invalid email addresses + "Abc.example.com", # no @ character + "A@b@c@example.com", # only one @ is allowed outside quotation marks + 'a"b(c)d,e:f;gi[j\\k]l@example.com', # none of the special characters in this local part are allowed outside quotation marks + 'just"not"right@example.com', # quoted strings must be dot separated or the only element making up the local-part + 'this is"not\\allowed@example.com', # spaces, quotes, and backslashes may only exist when within quoted strings and preceded by a backslash + 'this\\ still\\"not\\\\allowed@example.com', # even if escaped (preceded by a backslash), spaces, quotes, and backslashes must still be contained by quotes + "1234567890123456789012345678901234567890123456789012345678901234+x@example.com", # local part is longer than 64 characters + + # Emails with empty local part + "@example.com", # only valid if allow_empty_local is True + + # Emails with non-ASCII characters + "üñîçøðé@example.com", # only valid if allow_smtputf8 is True + "user@üñîçøðé.com", # only valid if allow_smtputf8 is True + + # Emails with quoted local part + '"john.doe"@example.com', # only valid if allow_quoted_local is True + '"john..doe"@example.com', # only valid if allow_quoted_local is True + + # Emails with display name + 'John Doe ', # only valid if allow_display_name is True + + # Emails with domain literal + 'user@[192.0.2.1]', # only valid if allow_domain_literal is True + + # Emails with long local part + "a"*65 + "@example.com", # local part is longer than 64 characters + + # Emails with invalid characters + "john doe@example.com", # space is not allowed + "john@doe@example.com", # only one @ is allowed + "john.doe@.com", # domain can't start with a dot + "john.doe@example..com", # domain can't have two consecutive dots + "test@google.com", + ] + + # create a list of configurations + configurations = [ + {"check_deliverability": True, "test_environment": False, "allow_smtputf8": False, "allow_empty_local": False, "allow_quoted_local": False, "allow_display_name": False, "allow_domain_literal": False, "globally_deliverable": None, "timeout": 10, "dns_type": 'timeout'}, + {"check_deliverability": False, "test_environment": True, "allow_smtputf8": True, "allow_empty_local": True, "allow_quoted_local": True, "allow_display_name": True, "allow_domain_literal": True, "globally_deliverable": None, "timeout": 5, "dns_type": 'dns'}, + {"check_deliverability": True}, + {"check_deliverability": False, "test_environment": False, "allow_smtputf8": True, "allow_empty_local": False, "allow_quoted_local": True, "allow_display_name": False, "allow_domain_literal": True, "globally_deliverable": None, "timeout": 15, "dns_type": 'timeout'}, + {"check_deliverability": True, "test_environment": True, "allow_smtputf8": False, "allow_empty_local": True, "allow_quoted_local": False, "allow_display_name": True, "allow_domain_literal": False, "globally_deliverable": None, "timeout": 20, "dns_type": 'dns'}, + {"check_deliverability": False, "test_environment": False, "allow_smtputf8": True, "allow_empty_local": True, "allow_quoted_local": True, "allow_display_name": True, "allow_domain_literal": True, "globally_deliverable": None, "timeout": 25, "dns_type": 'timeout'}, + {"check_deliverability": True, "test_environment": True, "allow_smtputf8": False, "allow_empty_local": False, "allow_quoted_local": False, "allow_display_name": False, "allow_domain_literal": False, "globally_deliverable": None, "timeout": 30, "dns_type": 'dns'}, + {"check_deliverability": False, "test_environment": True, "allow_smtputf8": True, "allow_empty_local": False, "allow_quoted_local": True, "allow_display_name": True, "allow_domain_literal": False, "globally_deliverable": None, "timeout": 35, "dns_type": 'timeout'}, + {"check_deliverability": True, "test_environment": False, "allow_smtputf8": False, "allow_empty_local": True, "allow_quoted_local": True, "allow_display_name": False, "allow_domain_literal": True, "globally_deliverable": None, "timeout": 40, "dns_type": 'dns'}, + {"check_deliverability": False, "test_environment": True, "allow_smtputf8": True, "allow_empty_local": False, "allow_quoted_local": False, "allow_display_name": True, "allow_domain_literal": True, "globally_deliverable": None, "timeout": 45, "dns_type": 'timeout'}, + ] + + t0 = time.time() + validity=[] + + for email in email_addresses: + for config in configurations: + + res = validate_email_address(email, **config) + validity.append(res) + t1 = time.time() + validity = sorted(validity, key=lambda x: x['email']) + + for v in validity: + pprint.pprint(v, indent=4) + + print(f"Time taken: {t1 - t0:.2f}") +``` diff --git a/dsg_lib/__init__.py b/dsg_lib/__init__.py index 2982891a..f141a76d 100644 --- a/dsg_lib/__init__.py +++ b/dsg_lib/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -__version__ = '0.12.3' +__version__ = '0.12.4' diff --git a/mkdocs.yml b/mkdocs.yml index e90a5d7a..715c0873 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,6 +34,7 @@ nav: - Async Database: 'recipes/asyncDatabase.md' - Logging: 'recipes/loggingExample.md' - Patterns: 'recipes/patterns.md' + - EmailValidation: 'recipes/emailValidation.md' - About: - Contributing: 'contribute.md' - Release Notes: release-notes.md diff --git a/pyproject.toml b/pyproject.toml index bdafb3e7..215bf465 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "hatchling.build" [project] name = "devsetgo_lib" -version = "0.12.3" +version = "0.12.4" requires-python = ">=3.9" description = "DevSetGo Common Library provides reusable Python functions for enhanced code efficiency. It includes utilities for file operations, calendar, pattern matching, logging, FastAPI endpoints, and async database handling with CRUD operations." readme = "README.md" @@ -34,6 +34,7 @@ classifiers = [ dependencies = [ "loguru>=0.7.0", "packaging>=20.0", + "email-validator>=2.1.1" ] # loguru = ">=0.7.0" # packaging = ">=20.0" diff --git a/requirements.txt b/requirements.txt index 746c6972..8656a961 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,7 @@ loguru==0.7.2 # Vulnerabilities: None mkdocs-material==9.5.23 # From 9.5.18 | Vulnerabilities: None mkdocs-print-site-plugin==2.4.1 # From 2.4.0 | Vulnerabilities: None mkdocstrings[python,shell]==0.25.1 # From 0.24.3 | Vulnerabilities: None + packaging==24.0 # Vulnerabilities: None pre-commit==3.7.1 # From 3.7.0 | Vulnerabilities: None psycopg2==2.9.9 # Vulnerabilities: None