Fri 14 May 2010
How to Send Email with Python
Posted by Mike under Cross-Platform, Python, System Administration
View Comments
Where I work, we run a number of login scripts written in Python. When an error occurs in one of those scripts, we want to know. So we wrote a simple Python script to email the error to us. Since then, I’ve needed to figure out a way to send attachments with some of my more advanced scripts. If you’re a long-time reader of this blog, then you may remember wxPyMail, which was a simple wxPython program that could send email. In this article, you’ll discover how to send email with just Python’s standard library. We will focus on smtplib and the email modules.
Sending Email with smtplib
Sending email with smtplib is super simple. Do you want to see how simple? Of course you do! Let’s take a look:
import smtplib import string SUBJECT = "Test email from Python" TO = "mike@mydomain.com" FROM = "python@mydomain.com" text = "blah blah blah" BODY = string.join(( "From: %s" % FROM, "To: %s" % TO, "Subject: %s" % SUBJECT , "", text ), "\r\n") server = smtplib.SMTP(HOST) server.sendmail(FROM, [TO], BODY) server.quit()
Notice that the actual connection and sending of the email was only two lines of code. The rest of the code was just setting up the message to send. At work, we wrap this all up in a callable function and pass it some information, like what the error was and who to send the error to. If you need to login, add a line right after you create the server variable where you do the following: server.login(username, password)
Send an Email with an Attachment
Now let’s look at how to send an email with an attachment. For this script, we’ll also use the email module. Here’s a simple example based on some code I wrote recently:
import os import smtplib from email import Encoders from email.MIMEBase import MIMEBase from email.MIMEMultipart import MIMEMultipart from email.Utils import formatdate filePath = r'\\some\path\to\a\file' def sendEmail(TO = "mike@mydomain.com", FROM="support@mydomain.com"): HOST = "mail.mydomain.com" msg = MIMEMultipart() msg["From"] = FROM msg["To"] = TO msg["Subject"] = "You've got mail!" msg['Date'] = formatdate(localtime=True) # attach a file part = MIMEBase('application', "octet-stream") part.set_payload( open(filePath,"rb").read() ) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(filePath)) msg.attach(part) server = smtplib.SMTP(HOST) # server.login(username, password) # optional try: failed = server.sendmail(FROM, TO, msg.as_string()) server.close() except Exception, e: errorMsg = "Unable to send email. Error: %s" % str(e) if __name__ == "__main__": sendEmail()
There’s a fair bit going on here, so let’s step through the new stuff. First we import all the bits and pieces we need from the email module. Then we create a nice function for sending email. Next we create a MIMEMultipart object. This handy object will hold our email. It uses a dict-like interface to add fields like TO, FROM, SUBJECT, etc. You’ll notice that we also have a date field. This just grabs your PC’s current date and converts it to the appropriate MIME email format.
The piece that we’re most interested in is how to attach a file. Here we create a MIMEBase object and set its payload to the file we want to attach. Note that we need to tell it to read the file as a binary file even if the file is in plain text. Next we encode the stream in base 64. The last two steps are to add a header and then attach the MIMEBase object to our MIMEMultipart object. If you had multiple files to attach, then you’d probably want to put this section into some kind of loop and loop over the files. In fact, that’s what I did in that wxPyMail example I mentioned earlier.
Anyway, once you’ve got all that done, then you do basically the same thing as you did in the smtplib example above. The only difference is that we changed the following line:
server.sendmail(FROM, TO, msg.as_string())
Note the msg.as_string. We needed to convert out object to a string to make this work. We also put the sendmail function inside a try/except statement in case something bad happens and our email fails to send. If we wanted to, we could have wrapped the try/except in a while loop so that we could retry sending the email X number of times if it failed.
Wrapping Up
We’ve covered how to send a simple email and how to send one with an attachment. The email module has lots more functionality built into it that is not covered here, so be sure to read the documentation. Have fun coding!
Additional Reading
- The smtplib module
- Python’s email module
If you want to include non-ASCII characters in your emails, you'll need to jump through a few more hoops: http://mg.pov.lt/blog/unicode-emails-in-python….
Thanks! I've been looking for a clear explanation of how to do this for a while.
email = MIMEText(mesg)
email['To'] = to
email['Subject'] = subject
mail_args = [SENDMAIL, '-t', '-f', ENV_SENDER]
mail = subprocess.Popen(mail_args, stdin=subprocess.PIPE)
print >>mail.stdin, email
mail.stdin.close()
Thanks for the hints. That could prove handy.
- Mike
Thanks for the link.
- Mike
I'm disappointed that this article, as with the docs at python.org, completely glosses over the need to do a DNS lookup for the MX records in order to find the HOST to which to make these SMTP connections.
As a long time sysadmin I know about MX records, now to look them up using 'dig' or even using the Python DNS module. However, many readers here won't. (Also there doesn't seem to be an easy way to do so from the Python standard libraries, one must either some some low level socket work, install the third party DNS module, or shell out (subprocess.Popen) and read the results back from some external tool such as 'dig' (and parse them, of course).
I know about MX records as well, but I'm not sure why you'd need to mess with those if all the smtplib wants is the host address, like mail.mydomain.com. I've never had to provide MX record info to Thunderbird or Outlook either. Could you explain some more about what you mean? I don't mind updating the article or writing a second one with additional information if I think it's valuable.
Thanks,
- Mike
I noticed that the Email message received does not have a subject while being displayed. Is there anyway to have subject line displayed? (so far subject is just in the same message body).
I love travelling so much that I often surfing on many journey forum to learn knowledge about trip, and I think this forum is the best, from where I got the newest information about journey. Here I want recommend some excellent websites http://www.mbt-outlet-store.com/mbt-men-shoes.html, There are many good products help you make a good journey.