How to Verify an Email Address in Python Using smtplib - python

I have been trying to verify an email address entered by the user in my program. The code I currently have is:
server = smtplib.SMTP()
server.connect()
server.set_debuglevel(True)
try:
server.verify(email)
except Exception:
return False
finally:
server.quit()
However when I run it I get:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
So what I am asking is how do i verify an email address using the smtp module? I want to check whether the email address actually exists.

Here's a simple way to verify emails. This is minimally modified code from this link. The first part will check if the email address is well-formed, the second part will ping the SMTP server with that address and see if it gets a success code (250) back or not. That being said, this isn't failsafe -- depending how this is set up sometimes every email will be returned as valid. So you should still send a verification email.
email_address = 'example#example.com'
#Step 1: Check email
#Check using Regex that an email meets minimum requirements, throw an error if not
addressToVerify = email_address
match = re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', addressToVerify)
if match == None:
print('Bad Syntax in ' + addressToVerify)
raise ValueError('Bad Syntax')
#Step 2: Getting MX record
#Pull domain name from email address
domain_name = email_address.split('#')[1]
#get the MX record for the domain
records = dns.resolver.query(domain_name, 'MX')
mxRecord = records[0].exchange
mxRecord = str(mxRecord)
#Step 3: ping email server
#check if the email address exists
# Get local server hostname
host = socket.gethostname()
# SMTP lib setup (use debug level for full output)
server = smtplib.SMTP()
server.set_debuglevel(0)
# SMTP Conversation
server.connect(mxRecord)
server.helo(host)
server.mail('me#domain.com')
code, message = server.rcpt(str(addressToVerify))
server.quit()
# Assume 250 as Success
if code == 250:
print('Y')
else:
print('N')

The server name isn't defined properly along with the port. Depending on how you have your SMTP server you might need to use the login function.
server = smtplib.SMTP(str(SERVER), int(SMTP_PORT))
server.connect()
server.set_debuglevel(True)
try:
server.verify(email)
except Exception:
return False
finally:
server.quit()

you need to specify the smtp host (server) in the SMTP construct. This depends on the email domain. eg for a gmail address you would need something like gmail-smtp-in.l.google.com.
The server.verify which is a SMTP VRFY probably isnt what you want though. Most servers disable it.
You might want to look at a service like Real Email which has guide for python. How to Validate Email Address in python.

Related

How to use SMTP with Apple iCloud Custom Domain

I would like to use Python's SMTP to send automated emails with a custom domain iCloud+ email address. However, I can't get logged into the SMTP servers. I will always either get "Mailbox does not exist" or "Authentication failed".
From the Apple support pages it seems like you need to use SSL over port 587. Additionally, they want you to generate an "app-specific password" for outside applications. This led me to the following code:
import smtplib, ssl
smtp_server = "smtp.mail.me.com"
port = 587 # For SSL
# Create a secure SSL context
context = ssl.create_default_context()
sender_email = "me#example.com" # Enter your address
receiver_email = "you#example.com" # Enter receiver address
password = "some,password" # app specific password from Apple ID settings
message = """\
To: {to}
From: {sender}
Subject: Hello There
This was sent through Python!
""".format(to=receiver_email, sender=sender_email)
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
server.login(sender_email, password)
# Send email here
server.sendmail(sender_email, receiver_email, message)
However, this was still giving me a connection error. Only when I changed the last part to use TLS instead would it connect and give me an authentication error. This was taken from this question: SMTP_SSL SSLError: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:590)
try:
server = smtplib.SMTP(smtp_server, port)
server.ehlo() # Can be omitted
server.starttls(context=context) # Secure the connection
server.ehlo() # Can be omitted
server.login(sender_email, password)
# Send email here
server.sendmail(sender_email, receiver_email, message)
except Exception as e:
import traceback
print(traceback.format_exc())
finally:
server.quit()
So how can I use my custom domain address with Apple's iCloud+ service with Python's SMTP?
Just before I was going to ask this question, I solved it!
After reading this reddit post, I figured that all custom domain iCloud+ accounts are actually alias of some sort to the main iCloud account. So, I tried logging into my "main" iCloud account. This worked with the above code and sent the email! However, the from was still not my custom domain email address.
This is a somewhat easy fix though, simply modify the "From: <sender>" line in the email body. I'm not sure if this should be done (since it's technicaly faking who you are) but it seems to work. If any email experts know of better ways to do this please comment/answer though! The following code is what I used:
sender_email = "me#icloud.com" # this is who we actually are
sender = "me#example.com" # this is who we appear to be (i.e. custom domain email)
receiver_email = "you#example.com" # this is to who we have sent the email
message = """\
To: {to}
From: {sender}
Subject: Hello There
This was sent through Python!
""".format(to=receiver_email, sender=sender) # this is what changed, we use an alias instead
# ...
server.sendmail(sender_email, receiver_email, message)

How can we check any Email Id is deliverable or not ( exist or not in real ) through program?

I have a huge list of email ids and I have to filter out all valid email ids , valid means really exist or not .
I am trying to implement smtplib for this but I am not sure about the right way. It gives random result for same email id, which is not exist (I have checked manually ) but it's showing sometimes exist and sometimes does not exit.
Is there any better or working method available ?
import socket
import smtplib
import dns.resolver
def get_connection_handler():
try:
# Get local server hostname
# host = socket.gethostname()
host = socket.getfqdn()
username = 'myemilid#gmail.com' #used with working email_id
password = 'password' #password
# SMTP lib setup (use debug level for full output)
server = smtplib.SMTP('smtp.gmail.com', 587, timeout=30)
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.login(username, password)
return host, server
except Exception as e:
return None, None
def validate_email_id(server, host, email_list):
for each_email_id in email_list:
records = dns.resolver.query(each_email_id.split('#')[-1], 'MX')
mxRecord = records[0].exchange
mxRecord = str(mxRecord)
# SMTP Conversation
server.connect(mxRecord)
server.helo(host)
server.mail('myemailid#gmail.com')
addressToVerify = 'ramanzzzzzooo#somedomain.com'
code, message = server.rcpt(str(addressToVerify))
email_list = ['email_id1#somedomain1.com','email_id1#somedomain2.com','email_id1#somedomain5.com','email_id1#somedomain4.com','email_id1#somedomain3.com',]
server,host = get_connection_handler()
validate_email_id(server,host,email_list)
It gives random result for same email_id, sometimes exist and sometimes does not.
Is there any other better way to do this ?
You can check if syntax is correct, just lookup the RFC, read it and run! The only sane check is really anything#anything.anything. So vaildate with a package like #Nick Predey suggested or only check for # and ..
The second part of your question is interesting. There is no method anymore to check if the e-mailaddress actually exists. In the early days there was finger to test if a user existed on a host. Nowadays that protocol isn't used anymore in the fight against spam (https://en.wikipedia.org/wiki/Finger_protocol)
The validate email python package could help you in this situation. According to the documentation, it is used to check whether an email is "valid, properly formatted and really exists."
After installing using pip install validate_email, you could use it like this:
from validate_email import validate_email
is_valid = validate_email('example#example.com')
Which returns true if the email is valid, false if not.

Python: check mail with smtplib and handle errors

I need to check emails programmatically. I'm using this code:
resolver = dns.resolver.Resolver()
resolver.timeout = 3
resolver.lifetime = 3
mx_records = resolver.query(domain, 'MX')
for mxRecord in mx_records:
mxRecord = str(mxRecord.exchange)
host = socket.gethostname()
server = smtplib.SMTP(timeout=30)
server.set_debuglevel(0)
addressToVerify = var0
server.connect(mxRecord)
server.helo(host)
server.mail('me#domain.com')
code, message = server.rcpt(str(addressToVerify))
server.quit()
res_email = 'Not Found'
if code == 250:
result = 'Success'
else:
print "doesn't exist"
I'm receiving an error when I run this code:
Connection unexpectedly closed
Connection unexpectedly closed: [Errno 10054]
[Errno 10061]
I have tried to change values of timeout, but it didn't help. I then tried to specify the port in smtplib.SMTP(), but specified 587 and that didn't resolve the issue either.
How can I solve this problem?
You can copy the code to interrogate a POP3 server from the Python help file. Here it is in ever-so-slightly modified form.
import poplib, getpass
pop = poplib.POP3('***********', port=110)
pop.user('**********')
pop.pass_('*********')
print (pop.stat())
print (pop.list()[1])
You have only to copy various constants such as the port number from your mail client.
What this script produces as output might surprise you, depending on the settings in your mail client. Here's what I just got.
(43, 1104784)
[b'1 15848', b'2 7889', b'3 7938', b'4 3705', b'5 28933', b'6 35479', b'7 12793', b'8 7094', b'9 10045', b'10 12793', b'11 17194', b'12 312802', b'13 12688', b'14 18431', b'15 24454', b'16 17769', b'17 16223', b'18 14975', b'19 11951', b'20 13373', b'21 34949', b'22 23647', b'23 14958', b'24 22449', b'25 5068', b'26 14920', b'27 8611', b'28 10982', b'29 14311', b'30 7477', b'31 3852', b'32 8497', b'33 4086', b'34 7240', b'35 69458', b'36 19430', b'37 110263', b'38 2434', b'39 12043', b'40 5306', b'41 10288', b'42 17164', b'43 74974']
But I know that no messages remain on the server that I haven't received in my mail client. The answer to this minor puzzle is that my email client leaves messages on the server for a fortnight, or until I delete them, by default, presumably as a safeguard against loss in case of some kind of computer failure.
This implies that it would be insufficient to simply use the above output as a check for new messages. It would be necessary to record dates from headers from received messages for up to a fortnight for comparison with those on the server.

No email sending using smtplib - python

import smtplib
sender = 'den.callanan#gmail.com'
receiver = ['callanden#gmail.com']
message = """From: From Person <den.callanan#gmail.com>
To: To Person <callanden#gmail.com>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
try:
print("trying host and port...")
smtpObj = smtplib.SMTP('smtp.gmail.com', 465)
print("sending mail...")
smtpObj.sendmail(sender, receiver, message)
print("Succesfully sent email")
except SMTPException:
print("Error: unable to send email")
I've created two new email accounts (above), both on the same server (gmail) to test this.
It reaches the point in which it prints "trying host and port..." and does not go any further. So the problem should be with the address and port number I entered. But according to gmail's outgoing mail server details i've inputted them correctly. Any ideas what's wrong?
If I remove the port number or try a different port number such as 587 i'm provided with an error.
Sending email via Gmail's SMTP servers requires TLS and authentication. To authenticate, you will need to make an application-specific password for your account.
This script worked for me (though I used my own GMail email address and my own application-specific password). In the code below, replace APPLICATION_SPECIFIC_PASSWORD with the password you generated.
import smtplib
sender = 'den.callanan#gmail.com'
receiver = ['callanden#gmail.com']
message = """From: From Person <den.callanan#gmail.com>
To: To Person <callanden#gmail.com>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
try:
print("trying host and port...")
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.login("den.callanan#gmail.com", "APPLICATION_SPECIFIC_PASSWORD")
print("sending mail...")
smtpObj.sendmail(sender, receiver, message)
print("Succesfully sent email")
except smtplib.SMTPException:
print("Error: unable to send email")
import traceback
traceback.print_exc()
(To debug the problem, I added the print-traceback code in the except statement. The exceptions had specific information on how to get it to work. The code hung when accessing port 465, I think because of problems with TLS negotiation, so I had to try using port 587; then I got good debugging info that explained what to do.)
You can see info on the SMTP_SSL object here.

Sending email with python smtplib not working, confused about the "from" field

I'm trying to send an email in python. Here is my code.
import smtplib
if __name__ == '__main__':
SERVER = "localhost"
FROM = "sender#example.com"
TO = ["wmh1993#gmail.com"] # must be a list
SUBJECT = "Hello!"
TEXT = "This message was sent with Python's smtplib."
# Prepare actual message
message = """\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
# Send the mail
server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO[0], message)
server.quit()
print "Message sent!"
This runs without error, but no email is sent to wmh1993#gmail.com.
Questions
One thing I don't understand about this code --- what restrictions do I have when setting the FROM field?
Do I somehow have to say that it was from my computer?
What is in place to prevent me from spoofing someone else's email?
Or am I at liberty to do that?
This runs without error, but no email is sent to wmh1993#gmail.com.
This usually means, the message was transferred to your MTA (mailserver) on 'localhost', but this server could not relay it to gmail. it probably tried to send a bounce message to "sender#example.com" and that failed as well. or it sent the message successfully but it landed in gmails spam folder (the message could trigger spam rules since it is missing a date header)
One thing I don't understand about this code --- what restrictions do I have when setting the FROM field?
it must be a syntactically valid email address
Do I somehow have to say that it was from my computer?
no. but that could be the problem why it was not delivered. is your computer on a home/dynamic/dial-up IP? gmail (and many many many other providers) don't accept mail from such IPs. the HELO of your mailserver might be wrong, DNS settings might be incorrect etc. you need to check the server logs. you probably have to configure your local mailserver to relay the message via a smarthost instead of trying to contact the target server directly.
What is in place to prevent me from spoofing someone else's email?
not much, that's why we have so much spam from forged adresses. things like SPF/DKIM can help a bit, but the SMTP protocol itself doesn't offer protection against spoofing.
Or am I at liberty to do that?
technically yes.
Well, since you don't specify exactly what kind of email server you are using and its settings, there are several things that might be wrong here.
First of all, you need to specify the HOST and the PORT of your server and connect to it.
Example:
HOST = "smtp.gmail.com"
PORT = "587"
SERVER = smtplib.SMTP()
SERVER.connect(HOST, PORT)
Then you need to specify an user and his password to this host.
Example:
USER = "myuser#gmail.com"
PASSWD = "123456"
Some servers require the TLS protocol.
Example:
SERVER.starttls()
Then you need to login.
Example:
SERVER.login(USER,PASSWD)
Only then you are able to send the email with your sendmail.
This example works pretty well in most common servers.
If you are using, as it seems, your own server, there aren't much changes you need to apply. But you need to know what kind of requirements this server has.
The "from" field in the email headers specifies the sender's email address. When using smtplib in Python to send an email, the "from" field can be set using the "from_address" argument in the smtplib.SMTP function. Here's an example:
import smtplib
sender_email = "sender#example.com"
recipient_email = "recipient#example.com"
message = "Subject: Example Email\n\nThis is an example email."
with smtplib.SMTP("smtp.example.com", 587) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.login("sender#example.com", "password")
smtp.sendmail(sender_email, recipient_email, message)
Note that many email servers may reject emails that have a "from" address that doesn't match the login credentials.

Categories