├── .gitignore ├── AUTHORS ├── INSTALL.txt ├── LICENSE ├── MANIFEST.in ├── README.rst ├── setup.py ├── vagrant_setup.md └── validate_email.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | build 3 | dist 4 | MANIFEST 5 | *.egg-info -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | validate_email was created by Syrus Akbary in 2 | April 2012. 3 | This package is based on the work of Noel Bush 4 | https://github.com/noelbush/py_email_validation -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | Thanks for downloading validate_email. 2 | 3 | To install it, make sure you have Python 2.2 or greater installed. Then run 4 | this command from the command prompt: 5 | 6 | python setup.py install -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Validate_email 2 | Copyright (c) 2014, Syrus Akbary, All rights reserved. 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 3.0 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library 16 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.rst -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Validate_email 3 | ============== 4 | 5 | Validate_email is a package for Python that check if an email is valid, properly formatted and really exists. 6 | 7 | 8 | 9 | INSTALLATION 10 | ============ 11 | 12 | First, you must do:: 13 | 14 | pip install validate_email 15 | 16 | Extra 17 | ------ 18 | 19 | For check the domain mx and verify email exits you must have the `pyDNS` package installed:: 20 | 21 | pip install pyDNS 22 | 23 | 24 | USAGE 25 | ===== 26 | 27 | Basic usage:: 28 | 29 | from validate_email import validate_email 30 | is_valid = validate_email('example@example.com') 31 | 32 | 33 | Checking domain has SMTP Server 34 | ------------------------------- 35 | 36 | Check if the host has SMTP Server:: 37 | 38 | from validate_email import validate_email 39 | is_valid = validate_email('example@example.com',check_mx=True) 40 | 41 | 42 | Verify email exists 43 | ------------------- 44 | 45 | Check if the host has SMTP Server and the email really exists:: 46 | 47 | from validate_email import validate_email 48 | is_valid = validate_email('example@example.com',verify=True) 49 | 50 | 51 | TODOs and BUGS 52 | ============== 53 | See: http://github.com/syrusakbary/validate_email/issues -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup(name='validate_email', 4 | version = '1.3', 5 | download_url = 'git@github.com:syrusakbary/validate_email.git', 6 | py_modules = ('validate_email',), 7 | author = 'Syrus Akbary', 8 | author_email = 'me@syrusakbary.com', 9 | description = 'validate_email verifies if an email address is valid and really exists.', 10 | long_description=open('README.rst').read(), 11 | keywords = 'email validation verification mx verify', 12 | url = 'http://github.com/syrusakbary/validate_email', 13 | license = 'LGPL', 14 | ) 15 | -------------------------------------------------------------------------------- /vagrant_setup.md: -------------------------------------------------------------------------------- 1 | How to Set Up Validate Email Using Vagrant on PC 2 | ------------------------------------------------- 3 | 4 | 1. Download Vagrant & Virtual Box 5 | * http://www.vagrantup.com/downloads 6 | * http://www.virtualbox.org/ 7 | 2. Look at http://docs.vagrantup.com/v2/getting-started/ to make a linux virtual machine via vagrant 8 | * tl;dr using bash (Can use regular Windows Terminal) 9 | * Make a folder first, whenever you want to access the vm you will need to cd into that folder 10 | ``` 11 | $ vagrant init hashicorp/precise32 12 | 13 | $ vagrant up 14 | 15 | $ vagrant ssh 16 | ``` 17 | * This last command is used to go into your vm 18 | 3. Install pipin the vm 19 | * http://www.saltycrane.com/blog/2010/02/how-install-pip-ubuntu/ 20 | * tl;dr 21 | ``` 22 | $ sudo apt-get install python-pip 23 | 24 | ``` 25 | 4. Install pyDNS 26 | ``` 27 | This is a package dependency of validate email 28 | 29 | $ sudo pip install pydns 30 | ``` 31 | 5. Install git 32 | ``` 33 | $ sudo apt-get install git 34 | ``` 35 | 6. Clone the validate_email repo to your vm 36 | * (Since its a new machine you will need to clone using the https url) 37 | * ```$ git clone git@github.com:efagerberg/validate_email.git``` 38 | * If you want to use your ssh keys on your machine you will need to add this line to the vagrant file under the config 39 | * Looks somthing like this: 40 | Vagrant::Config.run do |config| 41 | # stuff 42 | config.ssh.forward_agent = true 43 | end 44 | 7. cd into validate_email and run script 45 | ``` 46 | $ cd validate_email 47 | 48 | $ python validate_email.py 49 | ``` 50 | 51 | 52 | -------------------------------------------------------------------------------- /validate_email.py: -------------------------------------------------------------------------------- 1 | # RFC 2822 - style email validation for Python 2 | # (c) 2012 Syrus Akbary 3 | # Extended from (c) 2011 Noel Bush 4 | # for support of mx and user check 5 | # This code is made available to you under the GNU LGPL v3. 6 | # 7 | # This module provides a single method, valid_email_address(), 8 | # which returns True or False to indicate whether a given address 9 | # is valid according to the 'addr-spec' part of the specification 10 | # given in RFC 2822. Ideally, we would like to find this 11 | # in some other library, already thoroughly tested and well- 12 | # maintained. The standard Python library email.utils 13 | # contains a parse_addr() function, but it is not sufficient 14 | # to detect many malformed addresses. 15 | # 16 | # This implementation aims to be faithful to the RFC, with the 17 | # exception of a circular definition (see comments below), and 18 | # with the omission of the pattern components marked as "obsolete". 19 | 20 | import re 21 | import smtplib 22 | import logging 23 | import socket 24 | 25 | try: 26 | raw_input 27 | except NameError: 28 | def raw_input(prompt=''): 29 | return input(prompt) 30 | 31 | try: 32 | import DNS 33 | ServerError = DNS.ServerError 34 | DNS.DiscoverNameServers() 35 | except (ImportError, AttributeError): 36 | DNS = None 37 | 38 | class ServerError(Exception): 39 | pass 40 | 41 | # All we are really doing is comparing the input string to one 42 | # gigantic regular expression. But building that regexp, and 43 | # ensuring its correctness, is made much easier by assembling it 44 | # from the "tokens" defined by the RFC. Each of these tokens is 45 | # tested in the accompanying unit test file. 46 | # 47 | # The section of RFC 2822 from which each pattern component is 48 | # derived is given in an accompanying comment. 49 | # 50 | # (To make things simple, every string below is given as 'raw', 51 | # even when it's not strictly necessary. This way we don't forget 52 | # when it is necessary.) 53 | # 54 | WSP = r'[\s]' # see 2.2.2. Structured Header Field Bodies 55 | CRLF = r'(?:\r\n)' # see 2.2.3. Long Header Fields 56 | NO_WS_CTL = r'\x01-\x08\x0b\x0c\x0f-\x1f\x7f' # see 3.2.1. Primitive Tokens 57 | QUOTED_PAIR = r'(?:\\.)' # see 3.2.2. Quoted characters 58 | FWS = r'(?:(?:' + WSP + r'*' + CRLF + r')?' + \ 59 | WSP + r'+)' # see 3.2.3. Folding white space and comments 60 | CTEXT = r'[' + NO_WS_CTL + \ 61 | r'\x21-\x27\x2a-\x5b\x5d-\x7e]' # see 3.2.3 62 | CCONTENT = r'(?:' + CTEXT + r'|' + \ 63 | QUOTED_PAIR + r')' # see 3.2.3 (NB: The RFC includes COMMENT here 64 | # as well, but that would be circular.) 65 | COMMENT = r'\((?:' + FWS + r'?' + CCONTENT + \ 66 | r')*' + FWS + r'?\)' # see 3.2.3 67 | CFWS = r'(?:' + FWS + r'?' + COMMENT + ')*(?:' + \ 68 | FWS + '?' + COMMENT + '|' + FWS + ')' # see 3.2.3 69 | ATEXT = r'[\w!#$%&\'\*\+\-/=\?\^`\{\|\}~]' # see 3.2.4. Atom 70 | ATOM = CFWS + r'?' + ATEXT + r'+' + CFWS + r'?' # see 3.2.4 71 | DOT_ATOM_TEXT = ATEXT + r'+(?:\.' + ATEXT + r'+)*' # see 3.2.4 72 | DOT_ATOM = CFWS + r'?' + DOT_ATOM_TEXT + CFWS + r'?' # see 3.2.4 73 | QTEXT = r'[' + NO_WS_CTL + \ 74 | r'\x21\x23-\x5b\x5d-\x7e]' # see 3.2.5. Quoted strings 75 | QCONTENT = r'(?:' + QTEXT + r'|' + \ 76 | QUOTED_PAIR + r')' # see 3.2.5 77 | QUOTED_STRING = CFWS + r'?' + r'"(?:' + FWS + \ 78 | r'?' + QCONTENT + r')*' + FWS + \ 79 | r'?' + r'"' + CFWS + r'?' 80 | LOCAL_PART = r'(?:' + DOT_ATOM + r'|' + \ 81 | QUOTED_STRING + r')' # see 3.4.1. Addr-spec specification 82 | DTEXT = r'[' + NO_WS_CTL + r'\x21-\x5a\x5e-\x7e]' # see 3.4.1 83 | DCONTENT = r'(?:' + DTEXT + r'|' + \ 84 | QUOTED_PAIR + r')' # see 3.4.1 85 | DOMAIN_LITERAL = CFWS + r'?' + r'\[' + \ 86 | r'(?:' + FWS + r'?' + DCONTENT + \ 87 | r')*' + FWS + r'?\]' + CFWS + r'?' # see 3.4.1 88 | DOMAIN = r'(?:' + DOT_ATOM + r'|' + \ 89 | DOMAIN_LITERAL + r')' # see 3.4.1 90 | ADDR_SPEC = LOCAL_PART + r'@' + DOMAIN # see 3.4.1 91 | 92 | # A valid address will match exactly the 3.4.1 addr-spec. 93 | VALID_ADDRESS_REGEXP = '^' + ADDR_SPEC + '$' 94 | 95 | MX_DNS_CACHE = {} 96 | MX_CHECK_CACHE = {} 97 | 98 | 99 | def get_mx_ip(hostname): 100 | if hostname not in MX_DNS_CACHE: 101 | try: 102 | MX_DNS_CACHE[hostname] = DNS.mxlookup(hostname) 103 | except ServerError as e: 104 | if e.rcode == 3 or e.rcode == 2: # NXDOMAIN (Non-Existent Domain) or SERVFAIL 105 | MX_DNS_CACHE[hostname] = None 106 | else: 107 | raise 108 | 109 | return MX_DNS_CACHE[hostname] 110 | 111 | 112 | def validate_email(email, check_mx=False, verify=False, debug=False, smtp_timeout=10): 113 | """Indicate whether the given string is a valid email address 114 | according to the 'addr-spec' portion of RFC 2822 (see section 115 | 3.4.1). Parts of the spec that are marked obsolete are *not* 116 | included in this test, and certain arcane constructions that 117 | depend on circular definitions in the spec may not pass, but in 118 | general this should correctly identify any email address likely 119 | to be in use as of 2011.""" 120 | if debug: 121 | logger = logging.getLogger('validate_email') 122 | logger.setLevel(logging.DEBUG) 123 | else: 124 | logger = None 125 | 126 | try: 127 | assert re.match(VALID_ADDRESS_REGEXP, email) is not None 128 | check_mx |= verify 129 | if check_mx: 130 | if not DNS: 131 | raise Exception('For check the mx records or check if the email exists you must ' 132 | 'have installed pyDNS python package') 133 | hostname = email[email.find('@') + 1:] 134 | mx_hosts = get_mx_ip(hostname) 135 | if mx_hosts is None: 136 | return False 137 | for mx in mx_hosts: 138 | try: 139 | if not verify and mx[1] in MX_CHECK_CACHE: 140 | return MX_CHECK_CACHE[mx[1]] 141 | smtp = smtplib.SMTP(timeout=smtp_timeout) 142 | smtp.connect(mx[1]) 143 | MX_CHECK_CACHE[mx[1]] = True 144 | if not verify: 145 | try: 146 | smtp.quit() 147 | except smtplib.SMTPServerDisconnected: 148 | pass 149 | return True 150 | status, _ = smtp.helo() 151 | if status != 250: 152 | smtp.quit() 153 | if debug: 154 | logger.debug(u'%s answer: %s - %s', mx[1], status, _) 155 | continue 156 | smtp.mail('') 157 | status, _ = smtp.rcpt(email) 158 | if status == 250: 159 | smtp.quit() 160 | return True 161 | if debug: 162 | logger.debug(u'%s answer: %s - %s', mx[1], status, _) 163 | smtp.quit() 164 | except smtplib.SMTPServerDisconnected: # Server not permits verify user 165 | if debug: 166 | logger.debug(u'%s disconected.', mx[1]) 167 | except smtplib.SMTPConnectError: 168 | if debug: 169 | logger.debug(u'Unable to connect to %s.', mx[1]) 170 | return None 171 | except AssertionError: 172 | return False 173 | except (ServerError, socket.error) as e: 174 | if debug: 175 | logger.debug('ServerError or socket.error exception raised (%s).', e) 176 | return None 177 | return True 178 | 179 | if __name__ == "__main__": 180 | import time 181 | while True: 182 | email = raw_input('Enter email for validation: ') 183 | 184 | mx = raw_input('Validate MX record? [yN] ') 185 | if mx.strip().lower() == 'y': 186 | mx = True 187 | else: 188 | mx = False 189 | 190 | validate = raw_input('Try to contact server for address validation? [yN] ') 191 | if validate.strip().lower() == 'y': 192 | validate = True 193 | else: 194 | validate = False 195 | 196 | logging.basicConfig() 197 | 198 | result = validate_email(email, mx, validate, debug=True, smtp_timeout=1) 199 | if result: 200 | print("Valid!") 201 | elif result is None: 202 | print("I'm not sure.") 203 | else: 204 | print("Invalid!") 205 | 206 | time.sleep(1) 207 | 208 | 209 | # import sys 210 | 211 | # sys.modules[__name__],sys.modules['validate_email_module'] = validate_email,sys.modules[__name__] 212 | # from validate_email_module import * 213 | --------------------------------------------------------------------------------