Returns True if the passed email address is valid. The local part of the email precedes the singular @ symbol and is associated with a display-name. For example, "john.smith" The domain is stricter than the local part and follows the @ symbol. Global email checks: 1. Ther
(email: str)
| 41 | |
| 42 | |
| 43 | def is_valid_email_address(email: str) -> bool: |
| 44 | """ |
| 45 | Returns True if the passed email address is valid. |
| 46 | |
| 47 | The local part of the email precedes the singular @ symbol and |
| 48 | is associated with a display-name. For example, "john.smith" |
| 49 | The domain is stricter than the local part and follows the @ symbol. |
| 50 | |
| 51 | Global email checks: |
| 52 | 1. There can only be one @ symbol in the email address. Technically if the |
| 53 | @ symbol is quoted in the local-part, then it is valid, however this |
| 54 | implementation ignores "" for now. |
| 55 | (See https://en.wikipedia.org/wiki/Email_address#:~:text=If%20quoted,) |
| 56 | 2. The local-part and the domain are limited to a certain number of octets. With |
| 57 | unicode storing a single character in one byte, each octet is equivalent to |
| 58 | a character. Hence, we can just check the length of the string. |
| 59 | Checks for the local-part: |
| 60 | 3. The local-part may contain: upper and lowercase latin letters, digits 0 to 9, |
| 61 | and printable characters (!#$%&'*+-/=?^_`{|}~) |
| 62 | 4. The local-part may also contain a "." in any place that is not the first or |
| 63 | last character, and may not have more than one "." consecutively. |
| 64 | |
| 65 | Checks for the domain: |
| 66 | 5. The domain may contain: upper and lowercase latin letters and digits 0 to 9 |
| 67 | 6. Hyphen "-", provided that it is not the first or last character |
| 68 | 7. The domain may also contain a "." in any place that is not the first or |
| 69 | last character, and may not have more than one "." consecutively. |
| 70 | |
| 71 | >>> for email, valid in email_tests: |
| 72 | ... assert is_valid_email_address(email) == valid |
| 73 | """ |
| 74 | |
| 75 | # (1.) Make sure that there is only one @ symbol in the email address |
| 76 | if email.count("@") != 1: |
| 77 | return False |
| 78 | |
| 79 | local_part, domain = email.split("@") |
| 80 | # (2.) Check octet length of the local part and domain |
| 81 | if len(local_part) > MAX_LOCAL_PART_OCTETS or len(domain) > MAX_DOMAIN_OCTETS: |
| 82 | return False |
| 83 | |
| 84 | # (3.) Validate the characters in the local-part |
| 85 | if any( |
| 86 | char not in string.ascii_letters + string.digits + ".(!#$%&'*+-/=?^_`{|}~)" |
| 87 | for char in local_part |
| 88 | ): |
| 89 | return False |
| 90 | |
| 91 | # (4.) Validate the placement of "." characters in the local-part |
| 92 | if local_part.startswith(".") or local_part.endswith(".") or ".." in local_part: |
| 93 | return False |
| 94 | |
| 95 | # (5.) Validate the characters in the domain |
| 96 | if any(char not in string.ascii_letters + string.digits + ".-" for char in domain): |
| 97 | return False |
| 98 | |
| 99 | # (6.) Validate the placement of "-" characters |
| 100 | if domain.startswith("-") or domain.endswith("."): |
no test coverage detected