Wednesday, August 22, 2007

Sending emails via Gmail with Python

Whenever I need to send files from work to home I use gmail. Usually this email message consists of one single file (that may be a tarball) and has the file name for subject. In the "Automate Everything" spirit, I decided to build a script to do this task for me.

The first thing I had to do was find out how to send an email with an attachment via gmail. It wasn't too hard to find this information around the web, but it still took me the best part of an hour. So here's a simple Python script that sends an email with an attachment:

#!/usr/bin/python

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os

gmail_user = "your_email@gmail.com"
gmail_pwd = "your_password"

def mail(to, subject, text, attach):
msg = MIMEMultipart()

msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject

msg.attach(MIMEText(text))

part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)

mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, gmail_pwd)
mailServer.sendmail(gmail_user, to, msg.as_string())
# Should be mailServer.quit(), but that crashes...
mailServer.close()

mail("some.person@some.address.com",
"Hello from python!",
"This is a email sent with python",
"my_picture.jpg")

78 comments:

Sam said...

Yay! I need to do exactly this. Thank you so much for putting this recipe up here.

I'd written something similar using the old libgmail, but for whatever reason I can't get it working.

Thanks again!

alec said...

Awesome work, thanks.

Anonymous said...

There's a Nautilus script which allows us to send files to Gmail just right-clicking on the file and selecting "Send to Gmail".

It's called nautilus-send-gmail
http://mundogeek.net/nautilus-scripts/

Anonymous said...

Great !!!!

It works perfect.

Pierre said...

Thanks a lot! 3 minutes from googling to solving the issue, copy and paste included!

Thanks for posting this useful snippet.

Anonymous said...

Great peace of code.
Kudos to you my friend.

jont said...

Thanks of that it makes this logging app so much more useful
http://jamesoff.net/site/code/simplemonitor/

Anonymous said...

Thanks! Great script.
Adding command line options made it perfect for me: no options means the attachment is saved in my gmail account.
Very convenient.

Jyaif said...

daily database backup, here I come

Anonymous said...

Thanks - this is great and will save me a lot of time. I had it working in less than a minute.

cryptoj at yahoo dot com

Timur Izhbulatov said...

Well, at first glance I can't see how it differs from sending email through any other SMTP server. Is there anything gmail-specific I missed?

Josh said...

If I wasn't a guy, I would want to have your children.

Supriya said...

Awesome!
Million Thanks!!

Anonymous said...

This is good. Thank you. -A

Rico Chen said...

Hi this works great and the script would be more flexible if the attach becomes an optional argument:

def mail(to, subject, text,
attach=None):
  msg = MIMEMultipart()

  msg['From'] = gmail_user
  msg['To'] = to
  msg['Subject'] = subject

  msg.attach(MIMEText(text))
  if attach:
    part = MIMEBase('application', 'octet-stream')
    part.set_payload(open(attach, 'rb').read())
    Encoders.encode_base64(part)
    part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
    msg.attach(part)
...

mynthon said...

This is why python docs sux. This example should be there!

Thanx for grat script!

Anonymous said...

Works great! Thank you.

Nick said...

Thanks for this script, I used it to create a backup script for my dreamhost account. Read more on that on my blog.

Thanks again for sharing!

Björn said...

Hi, I tried this script at home (no proxy) and it works perfectly. At work, however, everything goes through a proxy server. I tried to find out how to adapt to that, but I didnt manage. Does anyone have a clue?
/bjorn

O said...

Great script!

I tried and the only change I had to make was to change the attach variable from "my_picture.jpg" to "/User/user_name_here/Desktop/FileName.jpg"

After that receiving the email with the picture in gmail was great!

Thanks!

Omar

Sirhc Senots said...
This comment has been removed by the author.
Sirhc Senots said...

I used your function to write my Inbox Poem Sender. http://welcometochrisworld.com/2009/03/24/inbox-poem-program/ Thanks

Anonymous said...

Excellent script! Any ideas how to make it work with Python 3.0? Thanks!

Alex said...

Great Script! Thank you!

Lionel said...

Very nice! I love how this was easy to search for...didnt have to kill myself to figure out how to do this

Knight Samar said...

Hey, thanks a lot!

This helped me confirm that I was on the right path because smtp.gmail.com sprouted "Auth not supported" msgs many times.

Keep blogging!

Aldo said...

man you are a Haaaaaaaaaacker. Great script.

I have one question.
How to specify multiple recipients?

Kutuma said...

Thank you all for the great comments!

@bjorn: Sorry, don't know how to make it work via a proxy server... I googled a bit, but couldn't find an answer (but I did find your question plenty of times!)

@Anonymous: Haven't tried it in Python 3.0... still haven't made the leap! :)

@Aldo: Haven't tested several recipients, but I believe you can just separate them by commas. E.g. "first@blah.net, second@blah.net"

Aldo said...

maybee this helps:

import os
from urllib2 import urlopen

# example proxy
os.environ['HTTP_PROXY']='http://169.229.50.9:3128'
try:
f = urlopen('http://www.google.com')
data = f.read()
f.close()
print 'Pass'
except:
print 'Fail'

John said...

Excellent I applaud you sir. Honestly your example works with gmail while "libgmail" is retarded and didn't even work with their sendmail.py script.

Anonymous said...

Great work, many thanks!

Greg said...

Thanks for posting your gmail program for Python! I have worked through dozens of other online examples and examples from books, and this is the first one that worked the way it was supposed to work. Very helpful! This is an excellent starting place for someone to build this kind of application and customize it for their own needs.

Anonymous said...

Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!

xpareto said...

KutumaSlistOfFans.add(ME)
GuidoSlistOfGeeks.add(Kutuma)

Pablo Rodriguez said...

Thanks man!!!! I didn't find anywhere a script that actually works =D

Anonymous said...

Genial fill someone in on and this fill someone in on helped me alot in my college assignement. Thank you for your information.

Conor said...

No license in the header... given that you've posted it, I'm sure you're OK with people drawing on this (realistically, outright copy/pasting, because it's so good!), but are there any specifics?

Should we assume GPL, Apache, CC-attribute, etc.?

Mel said...

Good deal love the code!

Juan Zuliani said...

EXCELENT!!!!!

Chris Morrell said...

Thanks for the code! Saved me time with my logging script.

Anonymous said...

Nice script, Very helpful for my home automation project

Kutuma said...

@Conor and everybody: You can assume Apache license for this (i.e. do whatever you want with the code, but I'm not responsible for it)

If you want to be extra-nice, add a comment to the blog, or post a link on twitter or facebook! :)

GamesBook said...

Good stuff... and if you don't want to store your password in a plain text file, then you can add this:

import getpass

gmail_pwd = getpass.getpass("GMail Password: ")

David said...

I wrote a script for my boss to turn a bunch of text files he generates every month into PDFs for him to email out. Then he was like, so can it mail them for me? And I said, "No, that kind of thing is way beyond my programming skills."

I should have known better than to underestimate how easy it is to do stuff with Python. Thanks Kutama.

Anonymous said...

from Italy: Grazie amico! Giusto, giusto lo script che stavo cercando.

Anonymous said...

great article, thanks!

Quentin said...

@Timur - you are correct, this is a standard smtplib conversation in python; I was looking for access through HTTP (thru a firewall).

As an aside, someone commented here last year "python docs suck". The docs are complete, but sometimes need augmentation. I start with these resources:

- http://www.doughellmann.com/PyMOTW/
- http://stackoverflow.com/questions/tagged/python

For example,
- http://www.doughellmann.com/PyMOTW/smtplib/index.html#module-smtplib
- http://stackoverflow.com/search?q=python+send+email
--
Quentin

digobh said...

Thank you so much for posting it.

Ashish Jain said...

I used this script today. It seems to work fine :). I started learning Python only a few weeks back. It would take ages to learn to do this with C++ simply because I think the existing libraries might have a huge learning curve. Python seems great so far.

Thanks a lot for posting.

Bút chì số said...

Thanks a lot ^^"

Near Privman said...

Thank you! Just what I needed.
You should update you code with Rico's suggestion. I ended up writing about the same thing before I saw Rico's comment.
Thanks to you too, Rico!

karan said...

I am behind a proxy and program is unable to resolve DNS issue.

Ryan said...

Any ideas on how to have Python set the font for the gmail message? Thanks!
- Ryan

Anonymous said...

Oy... why isn't this a part of the Python libraries? I thought their motto was batteries included?

Alve said...

Thanks so much my friend!

thejus said...

excellent..works like a charm..good work..

Sriram said...

Dude.. You're awesome, man! I'd been trying so hard to do this from the shell, and finally got back to good old python.
May u live long!!!

Sand said...

Hi there, thanks a lot .. this is good. Few questions:
1. Multiple attachments? (most urgent if possible)
2. Long text for message and subject.

sandip

rusty said...

Thanks.. this is a cool information. I would love to know how this really happens because I have been receiving so many unsolicited emails. I have reported the emails as spam but there are still a few that keeps on coming back to my inbox. nice post!
Hotmail

MauTau said...

Thank you so much for great script.
now i can send my log from keylogger in my machine with python script.

Anonymous said...

I tried running the program and got this error:


Traceback (most recent call last):
File "C:\Documents and Settings\User\My Documents\Programs\email.py", line 3, in
import smtplib
File "C:\Python27\lib\smtplib.py", line 46, in
import email.utils
File "C:\Documents and Settings\User\My Documents\Programs\email.py", line 4, in
from email.MIMEMultipart import MIMEMultipart
ImportError: No module named MIMEMultipart
>>>

what version of python are you using for this program? I ran it in python 2.7, I tried this in the module as well as just running it through windows.

Anonymous said...

Thanks, this saved me a lot of time.

Reynold said...

Thanks you so much :)

This script worked perfectly on python 2.x but on v3 it failed. I have modified this script(just the import section) and made it work on python v3.3 . Checkout the url pasted below for more info:)

https://jackal777.wordpress.com/2011/07/19/sending-emails-via-gmail-with-python3/

Wayne said...

Can i ask a dum question?

Where should I put the attachment file ? I mean I got a problem like this
IOError: [Errno 2] No such file or directory: 'my_picture.jpg'

Rajeev S said...

Thanks.........

Anonymous said...

This is awesome! Can someone please show how to make the attachment optional?

Thanks.

sijeesh kottakkal said...

Thanks...

M.R.K.Reddy said...

hi, I tried this script. I got error like this.

mail failed; [Errno 1] _ssl.c:499: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

can u please rectify this ticket.

Unknown said...

For me, this was the best posting on this topic that I've found over several days of hunting.

Much appreciated.

I have not yet figured out:
1) How to attach multiple files; and
2) Where to go (URLs) to learn about how the following stuff works:

msg.attach(MIMEText(text))

part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)

Any suggestions would be much appreciated.

Thanks again. This was very helpful for me.

Marc B. Hankin said...

For me, this was the best posting on this topic that I've found over several days of hunting.

Much appreciated.

I have not yet figured out:
1) How to attach multiple files; and
2) Where to go (URLs) to learn about how the following stuff works:

msg.attach(MIMEText(text))

part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)

Any suggestions would be much appreciated.

Thanks again. This was very helpful for me.

Anonymous said...

How many mails I can send per day using this program. My Aim is to send 2000 mails per day. Can any please help me how to send 2000 mails per day

izak said...

Really helpful! Nailed it immediately. Thanks for saving hours of working!

Hans from Holland said...

Katuma, THANKS for the script, wonderfull, keep up the good work!!

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...

#!/usr/bin/python

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os

gmail_user = "your_email@gmail.com"
gmail_pwd = "your_password"

def mail(to, subject, plain_text, html_text, attachment=None):
msg = MIMEMultipart('alternative')

msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject

msg.attach(MIMEText(plain_text, 'plain')) # attach plain text
msg.attach(MIMEText(html_text, 'html')) # attach html text

if attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)

mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, gmail_pwd)
mailServer.sendmail(gmail_user, to, msg.as_string())
# Should be mailServer.quit(), but that crashes...
mailServer.close()

mail("some.person@some.address.com",
"Hello from python!",
"This is a email sent with python", "<b>HTML Version</b>")

Sir Kushal Bhabra said...

Great work... works like a charm!

yigit said...

Good work! How could we send a mail with a body of local text file? Body is the content of txt file, not attached?