In our last tutorial, we showed you how to send emails through a Gmail server using a Python script. In this tutorial, you’ll learn how to access emails in your Gmail account via a Python script. We’ll use Python’s imap_tools library to automatically read emails and even download attachments from your Gmail account.
Generating Gmail App Password for Python
We discussed this at length in our last tutorial, but it’s worth mentioning again. You can’t use your Gmail password to access your Gmail account via a Python application. Instead, you need to generate a special app password that you’ll use to get into your Gmail account from within a Python application. The process to generate a Gmail App Password has been explained in detail in our last tutorial Basically, there are two steps involved:
-
To securely generate an app password, you need to enable 2-step verification for your Gmail account. To enable two step verification, login to your Gmail account and click this link.
-
After enabling two-step verification, you can generate app passwords. The steps for creating application password are explained here.
Once you have an app password, save it. You’ll need this password to log in to your Gmail account via a Python application, which we’re going to do right now.
Receiving Emails via a Python Application
To access emails from your Gmail account, you need your Gmail Id and the app password you generated in the previous step.
Let’s first enter your email address. The following script asks users to enter their email address in a hidden string. For the safety of your account, it’s always a good practice to enter emails and passwords in the form of hidden strings like this. To capture user input in a hidden format, you can use the getpass()
method of the “getpass” module as shown below:
import getpass
my_email = my_pass = getpass.getpass("Enter your email:")
Output:
Enter your email:········
Once you enter your email address, the next step is to enter the app password you just created. Execute the following script and enter your app password.
my_pass = getpass.getpass("Enter your app password:")
Output:
Enter your app password:········
Logging into your Gmail Account
You’ll be using Pythons imap_tools module to access the Gmail server and to login to your account. To download the imap_tools library, execute the following command on your command terminal.
$ pip install imap_tools
The following Python script shows how to connect and login to your Gmail account. The email and password are passed to the login()
method of the Mailbox class.
from imap_tools import MailBox
mailbox = MailBox('imap.gmail.com').login(my_email, my_pass )
Reading Emails
To access specific emails, you need to call the fetch()
method from your Mailbox class object. The first parameter for the fetch()
method is the search query string that filters your email. For example, the following script returns all the emails from your Gmail account containing a keyword fetch()
method returns a generator containing information about all the emails that satisfy the criteria defined by the search query.
You can iterate through all the emails and print a variety of information about the email using different attributes. For instance, the following script prints the email IDs, email subjects, and the date you received the emails.
for msg in mailbox.fetch('FROM "odesk"', charset='utf8'):
print("Message id:",msg.uid)
print("Message Subject:",msg.subject)
print("Message Date:", msg.date)
print("=============")
Here is a sample output of the above script.
Output:
Message id: 596
Message Subject: Welcome to oDesk, XYZ!
Message Date: 2015-03-11 05:10:54+00:00
=============
Message id: 601
Message Subject: Upcoming freelancer webinar: earning more on oDesk
Message Date: 2015-03-13 06:02:01-07:00
=============
Message id: 607
Message Subject: Pssst...can you keep a secret, XYZ?
Message Date: 2015-03-16 07:04:51-07:00
=============
Message id: 618
Message Subject: Offer: Need a 500-600 word blog post on JavaScript Promises (highly
technical) in 48 hours
Message Date: 2015-03-23 01:20:30+00:00
=============
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.
Details of search criteria supported by imap_tools library are described in the following table:
Key | Types | Results | Description | |
---|---|---|---|---|
answered | bool | ANSWERED | Opposite is UNANSWERED | with|without the Answered flag |
seen | bool | SEEN | Opposite is UNSEEN | with|without the Seen flag |
flagged | bool | FLAGGED | Opposite is UNFLAGGED | with|without the Flagged flag |
draft | bool | DRAFT | Opposite is UNDRAFT | with|without the Draft flag |
deleted | bool | DELETED | Opposite is UNDELETED | with|without the Deleted flag |
keyword | str* | KEYWORD KEY | with the specified keyword flag | |
no_keyword | str* | UNKEYWORD KEY | without the specified keyword flag | |
from_ | str* | FROM "from@ya.ru" | contain specified str in envelope struct's FROM field | |
to | str* | TO "to@ya.ru" | contain specified str in envelope struct's TO field | |
subject | str* | SUBJECT "hello" | contain specified str in envelope struct's SUBJECT field | |
body | str* | BODY "some_key" | contain specified str in body of the message | |
text | str* | TEXT "some_key" | contain specified str in header or body of the message | |
bcc | str* | BCC "bcc@ya.ru" | contain specified str in envelope struct's BCC field | |
cc | str* | CC "cc@ya.ru" | contain specified str in envelope struct's CC field | |
date | datetime.date* | ON 15-Mar-2000 | internal date is within specified date | |
date_gte | datetime.date* | SINCE 15-Mar-2000 | internal date is within or later than the specified date | |
date_lt | datetime.date* | BEFORE 15-Mar-2000 | internal date is earlier than the specified date | |
sent_date | datetime.date* | SENTON 15-Mar-2000 | rfc2822 Date: header is within the specified date | |
sent_date_gte | datetime.date* | SENTSINCE 15-Mar-2000 | rfc2822 Date: header is within or later than the specified date | |
sent_date_lt | datetime.date* | SENTBEFORE 1-Mar-2000 | rfc2822 Date: header is earlier than the specified date | |
size_gt | int >= 0 | LARGER 1024 | rfc2822 size larger than specified number of octets | |
size_lt | int >= 0 | SMALLER 512 | rfc2822 size smaller than specified number of octets | |
new | True | NEW | have the Recent flag set but not the Seen flag | |
old | True | OLD | do not have the Recent flag set | |
recent | True | RECENT | have the Recent flag set | |
all | True | ALL | all, criteria by default | |
uid | iter(str)/str/U | UID 1,2,17 | corresponding to the specified unique identifier set | |
header | H(str, str)* | HEADER "A-Spam" "5.8" | have a header that contains the specified str in the text | |
gmail_label | str* | X-GM-LABELS "label1" | have this gmail label. |
For more details about search criteria, check out the official documentation.
Let’s see another example demonstrating how to search an email with a particular subject line. To do so, you need to pass the string SUBJECT "Your subject line"
to the fetch()
method of the Mailbox class. The following script accesses the email with the subject
for msg in mailbox.fetch('SUBJECT "mobile_phones_list"', charset='utf8'):
print("Message id:",msg.uid)
print("Message Subject:",msg.subject)
print("Message Text:",msg.text)
print("Message Date:", msg.date)
Here is the output.
Output:
Message id: 13587
Message Subject: mobile_phones_list
Message Text: Here is a list of some famous mobile phones. please find the attachment.
Downloading Attachments from Email
You can also access and download attachments from your emails. To do so, you can use the attachment
attribute of the email. The following script prints the name and payload of the attachment in your email. The “payload” attribute actually contains the file contents in byte format.
for msg in mailbox.fetch('SUBJECT "mobile_phones_list"', charset='utf8'):
for att in msg.attachments:
print(att.filename)
print(att.payload)
Output:
Here is the output:
mobile_lists.jpg
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x03\x02\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05
The above output shows the file name, which is an image and the byte string for the file.
You can convert the bytes string containing your file content to an image file using the Image class. Look at the following script:
from imap_tools import MailBox
import getpass
import os
import io
import PIL.Image as Image
my_email = getpass.getpass("Enter your email:")
my_pass = getpass.getpass("Enter your app password:")
mailbox = MailBox('imap.gmail.com').login(my_email, my_pass )
for msg in mailbox.fetch('SUBJECT "mobile_phones_list"', charset='utf8'):
for att in msg.attachments:
print(att.filename)
bytes = att.payload
image = Image.open(io.BytesIO(bytes))
image.save(r"C:/"+att.filename)
Update the path where you want to save the image in the last line, then once you run the script, you’ll see the email attachment will be succefully downloaded to your local system.
Output:
mobile_lists.jpg
Finding a way to convert byte strings to a file like this is key to downloading Gmail attachments using Python. If you found this tutorial valuable, please subscribe using the form below so we can share other short, powerful Python tips we’ve learned through the years.
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.