Skip to content

Instantly share code, notes, and snippets.

@arulrajnet
Last active May 25, 2023 14:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save arulrajnet/c613bd0fad5de00bab2e to your computer and use it in GitHub Desktop.
Save arulrajnet/c613bd0fad5de00bab2e to your computer and use it in GitHub Desktop.
Verify the given mail id is valid or not, without sending mail. Verifying the email id directly from mail exchange server.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Verify the given mail id is valid or not without sending mail. Verifying the email id directly from mail exchange server.
"""
import argparse
import smtplib
import dns.resolver
import re
import logging
__author__ = 'arul'
class MXEmailVerifier():
FROM_ADDRESSES = ["info@gmail.com", "contact@gmail.com", "contact@yahoo.com", "info@yahoo.com",
"support@google.com"]
def __init__(self):
self.init_logging()
def init_logging(self):
"""
Initialize the logs
"""
global logger
logger = logging.getLogger('EmailVerifier')
logger.setLevel(logging.DEBUG)
# create console handler with a higher log level
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(console)
def __parse__(self, _email_):
"""
Parse and find the email id from the string using regex.
:param _email_:
:return:
"""
p_email = re.findall(r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b", _email_, re.I)
if p_email and len(p_email) > 0:
return p_email[0]
else:
raise ValueError("Not a valid email id %s." % _email_)
return None
def __find_mx_host__(self, _email_):
"""
It returns the mail exchange servers sorted by preference for the given mail id.
:param _email_:
:return:
"""
_host_ = _email_.split("@")[1]
answers = dns.resolver.query(_host_, 'MX')
# Sorting based on the preference
answers = sorted(answers, key=lambda answer: answer.preference)
hosts = list()
for rdata in answers:
hosts.append(rdata.exchange.to_text())
if hosts and len(hosts) > 0:
return hosts
else:
raise ValueError("MX server for host '%s' not able to find." % _host_)
return None
def verify(self, _email_):
"""
Verify the given email id is present in their mail exchange server.
:param _email_:
:return:
"""
# parsing given input as email id
parsed_email_id = self.__parse__(_email_)
logger.info("Parsed Email id : %s" % parsed_email_id)
# Finding mail exchange server of the parsed mail id
_mx_hosts_ = self.__find_mx_host__(parsed_email_id)
for _mx_host_ in _mx_hosts_:
_mx_host_ = _mx_host_[:-1] if _mx_host_[-1] == "." else _mx_host_
logger.debug("MX host is %s " % _mx_host_)
# Login into the mail exchange server
try:
smtp = smtplib.SMTP()
smtp.connect(_mx_host_)
except smtplib.SMTPConnectError, e:
logger.error(e)
continue
try:
smtp.ehlo_or_helo_if_needed()
except Exception, e:
logger.error(e)
continue
# First Try to verify with VRFY
# 250 is success code. 400 or greater is error.
v_code, v_message = smtp.verify(_email_)
logger.debug("VERIFY %s, %r" % (v_code, v_message))
if v_code and v_code != 250:
for _from_ in self.FROM_ADDRESSES:
f_code, f_message = smtp.mail(_from_)
logger.debug("FROM %s, %r" % (f_code, f_message))
# Then use RCPT to verify
if f_code and f_code == 250:
r_code, r_message = smtp.rcpt(_email_)
logger.debug("RCPT %s, %r" % (r_code, r_message))
if r_code and r_code == 250:
return True, r_message
if r_code and r_code == 550:
return False, r_message
else:
continue
else:
return True, v_message
smtp.quit()
break
return None, None
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Verify the given mail id is valid or not.")
parser.add_argument("-e", "--email", help='Enter the email id', required=True)
args = parser.parse_args()
verifier = MXEmailVerifier()
try:
verified, message = verifier.verify(args.email)
logger.info("%s, %s, %r" % (args.email, verified, message))
except Exception, e:
logger.error(e)
@arulrajnet
Copy link
Author

Installation

To use the above program, You have to install below modules.

dnspython - To make the DNS call such as nslookup.

argparse - Get an input from user

Command to Install

pip install dnspython argparse

How to use

python MXEmailVerifier.py -e larry@google.com

Output is

EmailVerifier - INFO - Parsed Email id : larry@google.com
EmailVerifier - DEBUG - MX host is aspmx.l.google.com
EmailVerifier - DEBUG - VERIFY 252, "2.1.5 Send some mail, I'll try my best sz3si6414611pab.188 - gsmtp"
EmailVerifier - DEBUG - FROM 250, '2.1.0 OK sz3si6414611pab.188 - gsmtp'
EmailVerifier - DEBUG - RCPT 250, '2.1.5 OK sz3si6414611pab.188 - gsmtp'
EmailVerifier - INFO - larry@google.com, True, '2.1.5 OK sz3si6414611pab.188 - gsmtp'

Where I can use

Suppose you are only knowing a person Name and where he/she is working. In that case you can use this program to verify their mail id with different pattern.

you can do the same via terminal using telnet http://superuser.com/a/224037/65918. I am automating that using python. Thats all.

@fahmi-rnf
Copy link

hi Arul, thanks a lot for your script, it's really help us to verify mail address

@haihoa
Copy link

haihoa commented Feb 2, 2016

You can see check valid email with code php http://emailchecker.info/

@nch-odoo
Copy link

Hi

I am trying to use your script but using this email xxx@spactro.com.do this fails here:

dns.resolver.query('spactro.com.do', 'MX')
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/dns/resolver.py", line 1102, in query
lifetime)
File "/usr/local/lib/python2.7/dist-packages/dns/resolver.py", line 1002, in query
raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses)
dns.resolver.NXDOMAIN: None of DNS query names exist: spactro.com.do., spactro.com.do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment