Created
November 9, 2015 22:28
-
-
Save phpdude/d608ce9d6297aca1c42d to your computer and use it in GitHub Desktop.
Validate Email Address in Python (part of django framework)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
class ValidationError(ValueError): | |
def __init__(self, message, code=None): | |
super(ValidationError, self).__init__(message) | |
self.code = code | |
def __str__(self): | |
return self.message | |
class EmailValidator(object): | |
message = 'Enter a valid email address.' | |
code = 'invalid' | |
user_regex = re.compile( | |
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom | |
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string | |
re.IGNORECASE) | |
domain_regex = re.compile( | |
# max length of the domain is 249: 254 (max email length) minus one | |
# period, two characters for the TLD, @ sign, & one character before @. | |
r'(?:[A-Z0-9](?:[A-Z0-9-]{0,247}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))\Z', | |
re.IGNORECASE) | |
literal_regex = re.compile( | |
# literal form, ipv4 or ipv6 address (SMTP 4.1.3) | |
r'\[([A-f0-9:\.]+)\]\Z', | |
re.IGNORECASE) | |
domain_whitelist = ['localhost'] | |
def __init__(self, message=None, code=None, whitelist=None): | |
if message is not None: | |
self.message = message | |
if code is not None: | |
self.code = code | |
if whitelist is not None: | |
self.domain_whitelist = whitelist | |
def __call__(self, value): | |
if not value or '@' not in value: | |
raise ValidationError(self.message, code=self.code) | |
user_part, domain_part = value.rsplit('@', 1) | |
if not self.user_regex.match(user_part): | |
raise ValidationError(self.message, code=self.code) | |
if (domain_part.lower() not in self.domain_whitelist and | |
not self.validate_domain_part(domain_part)): | |
# Try for possible IDN domain-part | |
try: | |
domain_part = domain_part.encode('idna').decode('ascii') | |
if self.validate_domain_part(domain_part): | |
return | |
except UnicodeError: | |
pass | |
raise ValidationError(self.message, code=self.code) | |
def validate_domain_part(self, domain_part): | |
if self.domain_regex.match(domain_part): | |
return True | |
return False | |
def __eq__(self, other): | |
return ( | |
isinstance(other, EmailValidator) and | |
(self.domain_whitelist == other.domain_whitelist) and | |
(self.message == other.message) and | |
(self.code == other.code) | |
) | |
def validate_email(email): | |
validator = EmailValidator() | |
validator(email) | |
return email |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment