mirror of
https://github.com/aljazceru/validate_email.git
synced 2025-12-19 15:14:18 +01:00
Merge pull request #6 from scardine/master
Suggestions for #4 and #2, general code janitoring.
This commit is contained in:
@@ -19,14 +19,18 @@
|
||||
|
||||
import re
|
||||
import smtplib
|
||||
import logging
|
||||
import socket
|
||||
|
||||
try:
|
||||
import DNS
|
||||
ServerError = DNS.ServerError
|
||||
except:
|
||||
except ImportError:
|
||||
DNS = None
|
||||
class ServerError(Exception): pass
|
||||
|
||||
class ServerError(Exception):
|
||||
pass
|
||||
|
||||
# All we are really doing is comparing the input string to one
|
||||
# gigantic regular expression. But building that regexp, and
|
||||
# ensuring its correctness, is made much easier by assembling it
|
||||
@@ -45,44 +49,44 @@ CRLF = r'(?:\r\n)' # see 2.2.3. Long Header Fi
|
||||
NO_WS_CTL = r'\x01-\x08\x0b\x0c\x0f-\x1f\x7f' # see 3.2.1. Primitive Tokens
|
||||
QUOTED_PAIR = r'(?:\\.)' # see 3.2.2. Quoted characters
|
||||
FWS = r'(?:(?:' + WSP + r'*' + CRLF + r')?' + \
|
||||
WSP + r'+)' # see 3.2.3. Folding white space and comments
|
||||
WSP + r'+)' # see 3.2.3. Folding white space and comments
|
||||
CTEXT = r'[' + NO_WS_CTL + \
|
||||
r'\x21-\x27\x2a-\x5b\x5d-\x7e]' # see 3.2.3
|
||||
r'\x21-\x27\x2a-\x5b\x5d-\x7e]' # see 3.2.3
|
||||
CCONTENT = r'(?:' + CTEXT + r'|' + \
|
||||
QUOTED_PAIR + r')' # see 3.2.3 (NB: The RFC includes COMMENT here
|
||||
# as well, but that would be circular.)
|
||||
QUOTED_PAIR + r')' # see 3.2.3 (NB: The RFC includes COMMENT here
|
||||
# as well, but that would be circular.)
|
||||
COMMENT = r'\((?:' + FWS + r'?' + CCONTENT + \
|
||||
r')*' + FWS + r'?\)' # see 3.2.3
|
||||
r')*' + FWS + r'?\)' # see 3.2.3
|
||||
CFWS = r'(?:' + FWS + r'?' + COMMENT + ')*(?:' + \
|
||||
FWS + '?' + COMMENT + '|' + FWS + ')' # see 3.2.3
|
||||
FWS + '?' + COMMENT + '|' + FWS + ')' # see 3.2.3
|
||||
ATEXT = r'[\w!#$%&\'\*\+\-/=\?\^`\{\|\}~]' # see 3.2.4. Atom
|
||||
ATOM = CFWS + r'?' + ATEXT + r'+' + CFWS + r'?' # see 3.2.4
|
||||
DOT_ATOM_TEXT = ATEXT + r'+(?:\.' + ATEXT + r'+)*' # see 3.2.4
|
||||
DOT_ATOM = CFWS + r'?' + DOT_ATOM_TEXT + CFWS + r'?' # see 3.2.4
|
||||
QTEXT = r'[' + NO_WS_CTL + \
|
||||
r'\x21\x23-\x5b\x5d-\x7e]' # see 3.2.5. Quoted strings
|
||||
r'\x21\x23-\x5b\x5d-\x7e]' # see 3.2.5. Quoted strings
|
||||
QCONTENT = r'(?:' + QTEXT + r'|' + \
|
||||
QUOTED_PAIR + r')' # see 3.2.5
|
||||
QUOTED_PAIR + r')' # see 3.2.5
|
||||
QUOTED_STRING = CFWS + r'?' + r'"(?:' + FWS + \
|
||||
r'?' + QCONTENT + r')*' + FWS + \
|
||||
r'?' + r'"' + CFWS + r'?'
|
||||
r'?' + QCONTENT + r')*' + FWS + \
|
||||
r'?' + r'"' + CFWS + r'?'
|
||||
LOCAL_PART = r'(?:' + DOT_ATOM + r'|' + \
|
||||
QUOTED_STRING + r')' # see 3.4.1. Addr-spec specification
|
||||
QUOTED_STRING + r')' # see 3.4.1. Addr-spec specification
|
||||
DTEXT = r'[' + NO_WS_CTL + r'\x21-\x5a\x5e-\x7e]' # see 3.4.1
|
||||
DCONTENT = r'(?:' + DTEXT + r'|' + \
|
||||
QUOTED_PAIR + r')' # see 3.4.1
|
||||
QUOTED_PAIR + r')' # see 3.4.1
|
||||
DOMAIN_LITERAL = CFWS + r'?' + r'\[' + \
|
||||
r'(?:' + FWS + r'?' + DCONTENT + \
|
||||
r')*' + FWS + r'?\]' + CFWS + r'?' # see 3.4.1
|
||||
r'(?:' + FWS + r'?' + DCONTENT + \
|
||||
r')*' + FWS + r'?\]' + CFWS + r'?' # see 3.4.1
|
||||
DOMAIN = r'(?:' + DOT_ATOM + r'|' + \
|
||||
DOMAIN_LITERAL + r')' # see 3.4.1
|
||||
DOMAIN_LITERAL + r')' # see 3.4.1
|
||||
ADDR_SPEC = LOCAL_PART + r'@' + DOMAIN # see 3.4.1
|
||||
|
||||
# A valid address will match exactly the 3.4.1 addr-spec.
|
||||
VALID_ADDRESS_REGEXP = '^' + ADDR_SPEC + '$'
|
||||
|
||||
def validate_email(email, check_mx=False,verify=False):
|
||||
|
||||
def validate_email(email, check_mx=False, verify=False, debug=False):
|
||||
"""Indicate whether the given string is a valid email address
|
||||
according to the 'addr-spec' portion of RFC 2822 (see section
|
||||
3.4.1). Parts of the spec that are marked obsolete are *not*
|
||||
@@ -90,13 +94,21 @@ def validate_email(email, check_mx=False,verify=False):
|
||||
depend on circular definitions in the spec may not pass, but in
|
||||
general this should correctly identify any email address likely
|
||||
to be in use as of 2011."""
|
||||
if debug:
|
||||
logger = logging.getLogger('validate_email')
|
||||
logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
logger = None
|
||||
|
||||
try:
|
||||
assert re.match(VALID_ADDRESS_REGEXP, email) is not None
|
||||
check_mx |= verify
|
||||
if check_mx:
|
||||
if not DNS: raise Exception('For check the mx records or check if the email exists you must have installed pyDNS python package')
|
||||
if not DNS:
|
||||
raise Exception('For check the mx records or check if the email exists you must '
|
||||
'have installed pyDNS python package')
|
||||
DNS.DiscoverNameServers()
|
||||
hostname = email[email.find('@')+1:]
|
||||
hostname = email[email.find('@') + 1:]
|
||||
mx_hosts = DNS.mxlookup(hostname)
|
||||
for mx in mx_hosts:
|
||||
try:
|
||||
@@ -108,22 +120,62 @@ def validate_email(email, check_mx=False,verify=False):
|
||||
status, _ = smtp.helo()
|
||||
if status != 250:
|
||||
smtp.quit()
|
||||
if debug:
|
||||
logger.debug(u'%s answer: %s - %s', mx[1], status, _)
|
||||
continue
|
||||
smtp.mail('')
|
||||
status, _ = smtp.rcpt(email)
|
||||
if status != 250:
|
||||
if status == 250:
|
||||
smtp.quit()
|
||||
return False
|
||||
return True
|
||||
if debug:
|
||||
logger.debug(u'%s answer: %s - %s', mx[1], status, _)
|
||||
smtp.quit()
|
||||
break
|
||||
except smtplib.SMTPServerDisconnected: #Server not permits verify user
|
||||
break
|
||||
except smtplib.SMTPServerDisconnected: # Server not permits verify user
|
||||
if debug:
|
||||
logger.debug(u'%s disconected.', mx[1])
|
||||
except smtplib.SMTPConnectError:
|
||||
continue
|
||||
except (AssertionError, ServerError):
|
||||
if debug:
|
||||
logger.debug(u'Unable to connect to %s.', mx[1])
|
||||
return None
|
||||
except AssertionError:
|
||||
return False
|
||||
except (ServerError, socket.error) as e:
|
||||
if debug:
|
||||
logger.debug('ServerError or socket.error exception raised (%s).', e)
|
||||
return None
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
import time
|
||||
while True:
|
||||
email = raw_input('Enter email for validation: ')
|
||||
|
||||
mx = raw_input('Validate MX record? [yN] ')
|
||||
if mx.strip().lower() == 'y':
|
||||
mx = True
|
||||
else:
|
||||
mx = False
|
||||
|
||||
validate = raw_input('Try to contact server for address validation? [yN] ')
|
||||
if validate.strip().lower() == 'y':
|
||||
validate = True
|
||||
else:
|
||||
validate = False
|
||||
|
||||
logging.basicConfig()
|
||||
|
||||
result = validate_email(email, mx, validate, debug=True)
|
||||
if result:
|
||||
print "Valid!"
|
||||
elif result is None:
|
||||
print "I'm not sure."
|
||||
else:
|
||||
print "Invalid!"
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
# import sys
|
||||
|
||||
# sys.modules[__name__],sys.modules['validate_email_module'] = validate_email,sys.modules[__name__]
|
||||
|
||||
Reference in New Issue
Block a user