154

I'm using the following method to send mail from Python using SMTP. Is it the right method to use or are there gotchas I'm missing ?

from smtplib import SMTP import datetime debuglevel = 0 smtp = SMTP() smtp.set_debuglevel(debuglevel) smtp.connect('YOUR.MAIL.SERVER', 26) smtp.login('USERNAME@DOMAIN', 'PASSWORD') from_addr = "John Doe <[email protected]>" to_addr = "[email protected]" subj = "hello" date = datetime.datetime.now().strftime( "%d/%m/%Y %H:%M" ) message_text = "Hello\nThis is a mail from your server\n\nBye\n" msg = "From: %s\nTo: %s\nSubject: %s\nDate: %s\n\n%s" % ( from_addr, to_addr, subj, date, message_text ) smtp.sendmail(from_addr, to_addr, msg) smtp.quit() 
5

16 Answers 16

148

The script I use is quite similar; I post it here as an example of how to use the email.* modules to generate MIME messages; so this script can be easily modified to attach pictures, etc.

I rely on my ISP to add the date time header.

My ISP requires me to use a secure smtp connection to send mail, I rely on the smtplib module (downloadable at http://www1.cs.columbia.edu/~db2501/ssmtplib.py)

As in your script, the username and password, (given dummy values below), used to authenticate on the SMTP server, are in plain text in the source. This is a security weakness; but the best alternative depends on how careful you need (want?) to be about protecting these.

=======================================

#! /usr/local/bin/python SMTPserver = 'smtp.att.yahoo.com' sender = 'me@my_email_domain.net' destination = ['recipient@her_email_domain.com'] USERNAME = "USER_NAME_FOR_INTERNET_SERVICE_PROVIDER" PASSWORD = "PASSWORD_INTERNET_SERVICE_PROVIDER" # typical values for text_subtype are plain, html, xml text_subtype = 'plain' content="""\ Test message """ subject="Sent from Python" import sys from smtplib import SMTP_SSL as SMTP # this invokes the secure SMTP protocol (port 465, uses SSL) # from smtplib import SMTP # use this for standard SMTP protocol (port 25, no encryption) # old version # from email.MIMEText import MIMEText from email.mime.text import MIMEText try: msg = MIMEText(content, text_subtype) msg['Subject']= subject msg['From'] = sender # some SMTP servers will do this automatically, not all conn = SMTP(SMTPserver) conn.set_debuglevel(False) conn.login(USERNAME, PASSWORD) try: conn.sendmail(sender, destination, msg.as_string()) finally: conn.quit() except: sys.exit( "mail failed; %s" % "CUSTOM_ERROR" ) # give an error message 
Sign up to request clarification or add additional context in comments.

9 Comments

@Vincent: mail failed; 'module' object has no attribute 'SSLFakeSocket' - using Gmail :(
This sounds like a version or import problem, to help track it down: What version Python are you running? -- Do you need to connect to your SMTP server over SSL (and if so are you importing ssmtplib, as above)? Can you import smtplib directly from python interactive, if so, is there a smtplib.SSLFakeSocket class defined? Hope I can help
Use smtplib.SMTP_SSL (standard in latest versions of Python) to create the connection instead of ssmtplib.STMP_SSL (third party module hinted above). Notice the standard module begins with a single 's'. That worked for me.
replace from ssmtplib import SMTP_SSL as SMTP with from smtplib import SMTP_SSL as SMTP, and this example would work from the standard Python library.
Add msg['To'] = ','.join(destination), Otherwise destination is not viewed in gmail
|
118

The method I commonly use...not much different but a little bit

import smtplib from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText msg = MIMEMultipart() msg['From'] = '[email protected]' msg['To'] = '[email protected]' msg['Subject'] = 'simple email in python' message = 'here is the email' msg.attach(MIMEText(message)) mailserver = smtplib.SMTP('smtp.gmail.com',587) # identify ourselves to smtp gmail client mailserver.ehlo() # secure our email with tls encryption mailserver.starttls() # re-identify ourselves as an encrypted connection mailserver.ehlo() mailserver.login('[email protected]', 'mypassword') mailserver.sendmail('[email protected]','[email protected]',msg.as_string()) mailserver.quit() 

That's it

3 Comments

If you use 2 Step Verification, you have to create an App specific password first and replace your normal password with it. See Sign in using App Passwords
I agree, this is the best answer and should be accepted. The one which is actually accepted is inferior.
For python3, use: from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
24

Also if you want to do smtp auth with TLS as opposed to SSL then you just have to change the port (use 587) and do smtp.starttls(). This worked for me:

... smtp.connect('YOUR.MAIL.SERVER', 587) smtp.ehlo() smtp.starttls() smtp.ehlo() smtp.login('USERNAME@DOMAIN', 'PASSWORD') ... 

Comments

8

What about this?

import smtplib SERVER = "localhost" FROM = "[email protected]" TO = ["[email protected]"] # 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, message) server.quit() 

Comments

7

following code is working fine for me:

import smtplib to = '[email protected]' gmail_user = '[email protected]' gmail_pwd = 'yourpassword' smtpserver = smtplib.SMTP("smtp.gmail.com",587) smtpserver.ehlo() smtpserver.starttls() smtpserver.ehlo() smtpserver.login(gmail_user, gmail_pwd) header = 'To:' + to + '\n' + 'From: ' + gmail_user + '\n' + 'Subject:testing \n' print header msg = header + '\n this is test msg from mkyong.com \n\n' smtpserver.sendmail(gmail_user, to, msg) print 'done!' smtpserver.quit() 

Ref: http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/

Comments

6

Make sure you don't have any firewalls blocking SMTP. The first time I tried to send an email, it was blocked both by Windows Firewall and McAfee - took forever to find them both.

Comments

6

Based on this example I made following function:

import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText def send_email(host, port, user, pwd, recipients, subject, body, html=None, from_=None): """ copied and adapted from https://stackoverflow.com/questions/10147455/how-to-send-an-email-with-gmail-as-provider-using-python#12424439 returns None if all ok, but if problem then returns exception object """ PORT_LIST = (25, 587, 465) FROM = from_ if from_ else user TO = recipients if isinstance(recipients, (list, tuple)) else [recipients] SUBJECT = subject TEXT = body.encode("utf8") if isinstance(body, unicode) else body HTML = html.encode("utf8") if isinstance(html, unicode) else html if not html: # Prepare actual message message = """From: %s\nTo: %s\nSubject: %s\n\n%s """ % (FROM, ", ".join(TO), SUBJECT, TEXT) else: # https://stackoverflow.com/questions/882712/sending-html-email-using-python#882770 msg = MIMEMultipart('alternative') msg['Subject'] = SUBJECT msg['From'] = FROM msg['To'] = ", ".join(TO) # Record the MIME types of both parts - text/plain and text/html. # utf-8 -> https://stackoverflow.com/questions/5910104/python-how-to-send-utf-8-e-mail#5910530 part1 = MIMEText(TEXT, 'plain', "utf-8") part2 = MIMEText(HTML, 'html', "utf-8") # Attach parts into message container. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. msg.attach(part1) msg.attach(part2) message = msg.as_string() try: if port not in PORT_LIST: raise Exception("Port %s not one of %s" % (port, PORT_LIST)) if port in (465,): server = smtplib.SMTP_SSL(host, port) else: server = smtplib.SMTP(host, port) # optional server.ehlo() if port in (587,): server.starttls() server.login(user, pwd) server.sendmail(FROM, TO, message) server.close() # logger.info("SENT_EMAIL to %s: %s" % (recipients, subject)) except Exception, ex: return ex return None 

if you pass only body then plain text mail will be sent, but if you pass html argument along with body argument, html email will be sent (with fallback to text content for email clients that don't support html/mime types).

Example usage:

ex = send_email( host = 'smtp.gmail.com' #, port = 465 # OK , port = 587 #OK , user = "[email protected]" , pwd = "xxx" , from_ = '[email protected]' , recipients = ['[email protected]'] , subject = "Test from python" , body = "Test from python - body" ) if ex: print("Mail sending failed: %s" % ex) else: print("OK - mail sent" 

Btw. If you want to use gmail as testing or production SMTP server, enable temp or permanent access to less secured apps:

1 Comment

Note that from May 30, 2022 you must use two-step auth to connect to your google account. Allowing access to less secured apps is not a thing anymore :)
6

The main gotcha I see is that you're not handling any errors: .login() and .sendmail() both have documented exceptions that they can throw, and it seems like .connect() must have some way to indicate that it was unable to connect - probably an exception thrown by the underlying socket code.

Comments

5

Or

import smtplib from email.message import EmailMessage from getpass import getpass password = getpass() message = EmailMessage() message.set_content('Message content here') message['Subject'] = 'Your subject here' message['From'] = "USERNAME@DOMAIN" message['To'] = "[email protected]" try: smtp_server = None smtp_server = smtplib.SMTP("YOUR.MAIL.SERVER", 587) smtp_server.ehlo() smtp_server.starttls() smtp_server.ehlo() smtp_server.login("USERNAME@DOMAIN", password) smtp_server.send_message(message) except Exception as e: print("Error: ", str(e)) finally: if smtp_server is not None: smtp_server.quit() 

If you want to use Port 465 you have to create an SMTP_SSL object.

Comments

4

The example code which i did for send mail using SMTP.

import smtplib, ssl smtp_server = "smtp.gmail.com" port = 587 # For starttls sender_email = "sender@email" receiver_email = "receiver@email" password = "<your password here>" message = """ Subject: Hi there This message is sent from Python.""" # Create a secure SSL context context = ssl.create_default_context() # Try to log in to server and send email server = smtplib.SMTP(smtp_server,port) try: server.ehlo() # Can be omitted server.starttls(context=context) # Secure the connection server.ehlo() # Can be omitted server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message) except Exception as e: # Print any error messages to stdout print(e) finally: server.quit() 

Comments

3

You should make sure you format the date in the correct format - RFC2822.

Comments

3

Based on madman2890, updated a few things as well as removed the need for mailserver.quit()

import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText msg = MIMEMultipart() msg['From'] = '[email protected]' msg['To'] = '[email protected]' msg['Subject'] = 'simple email in python' message = 'here is the email' msg.attach(MIMEText(message)) with smtplib.SMTP('smtp-mail.outlook.com',587) as mail_server: # identify ourselves to smtp gmail client mail_server.ehlo() # secure our email with tls encryption mail_server.starttls() # re-identify ourselves as an encrypted connection mail_server.ehlo() mail_server.login('[email protected]', 'mypassword') mail_server.sendmail('[email protected]','[email protected]',msg.as_string()) 

Comments

2

See all those lenghty answers? Please allow me to self promote by doing it all in a couple of lines.

Import and Connect:

import yagmail yag = yagmail.SMTP('[email protected]', host = 'YOUR.MAIL.SERVER', port = 26) 

Then it is just a one-liner:

yag.send('[email protected]', 'hello', 'Hello\nThis is a mail from your server\n\nBye\n') 

It will actually close when it goes out of scope (or can be closed manually). Furthermore, it will allow you to register your username in your keyring such that you do not have to write out your password in your script (it really bothered me prior to writing yagmail!)

For the package/installation, tips and tricks please look at git or pip, available for both Python 2 and 3.

2 Comments

@PascalvKoolen I installed yagmail, and tried connecting by giving my email id and password. but it gave me an authentication error
keyring missing: NameError: name 'keyring' is not defined. Use: pip install keyring.
2

you can do like that

import smtplib from email.mime.text import MIMEText from email.header import Header server = smtplib.SMTP('mail.servername.com', 25) server.ehlo() server.starttls() server.login('username', 'password') from = '[email protected]' to = '[email protected]' body = 'That A Message For My Girl Friend For tell Him If We will go to eat Something This Nigth' subject = 'Invite to A Diner' msg = MIMEText(body,'plain','utf-8') msg['Subject'] = Header(subject, 'utf-8') msg['From'] = Header(from, 'utf-8') msg['To'] = Header(to, 'utf-8') message = msg.as_string() server.sendmail(from, to, message) 

Comments

1

Here's a working example for Python 3.x

#!/usr/bin/env python3 from email.message import EmailMessage from getpass import getpass from smtplib import SMTP_SSL from sys import exit smtp_server = 'smtp.gmail.com' username = '[email protected]' password = getpass('Enter Gmail password: ') sender = '[email protected]' destination = '[email protected]' subject = 'Sent from Python 3.x' content = 'Hello! This was sent to you via Python 3.x!' # Create a text/plain message msg = EmailMessage() msg.set_content(content) msg['Subject'] = subject msg['From'] = sender msg['To'] = destination try: s = SMTP_SSL(smtp_server) s.login(username, password) try: s.send_message(msg) finally: s.quit() except Exception as E: exit('Mail failed: {}'.format(str(E))) 

Comments

1

What about Red Mail?

Install it:

pip install redmail 

Then just:

from redmail import EmailSender # Configure the sender email = EmailSender( host="YOUR.MAIL.SERVER", port=26, username='[email protected]', password='<PASSWORD>' ) # Send an email: email.send( subject="An example email", sender="[email protected]", receivers=['[email protected]'], text="Hello!", html="<h1>Hello!</h1>" ) 

It has quite a lot of features:

Links:

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.