Being able to create an application that is able to read your emails and automatically downloading attachments is a handy tool. In this tutorial, you will learn how to use the built-in imaplib module to list and read your emails in Python, we gonna need the help of IMAP protocol.
IMAP is an Internet standard protocol used by email clients to retrieve email messages from a mail server. Unlike the POP3 protocol which downloads email and delete them from the server (and then read them offline), with IMAP, the message does not remain on the local computer, it stays on the server.
If you want to read emails with Python using some sort of API instead of imaplib, you can check the tutorial on how to use Gmail API where we cover that out.
To get started, we don't have to install anything, all the modules used in this tutorial are the built-in ones:
import imaplib import email from email.header import decode_header import webbrowser import os # account credentials username = "[email protected]" password = "yourpassword" def clean(text): # clean text for creating a folder return "".join(c if c.isalnum() else "_" for c in text)
We've imported the necessary modules, and then specified the credentials of our email account. We gonna need the
clean() function later to create folders without spaces and special characters.
First, we gonna need to connect to the IMAP server:
# create an IMAP4 class with SSL imap = imaplib.IMAP4_SSL("imap.gmail.com") # authenticate imap.login(username, password)
Since I'm testing this on a gmail account, I've used
imap.gmail.com server, check this link that contains list of IMAP servers for most commonly used email providers.
Also, if you're using a Gmail account and the above code raises an error indicating that the credentials are incorrect, make sure you allow less secure apps
status, messages = imap.select("INBOX") # number of top emails to fetch N = 3 # total number of emails messages = int(messages)
for i in range(messages, messages-N, -1): # fetch the email message by ID res, msg = imap.fetch(str(i), "(RFC822)") for response in msg: if isinstance(response, tuple): # parse a bytes email into a message object msg = email.message_from_bytes(response) # decode the email subject subject, encoding = decode_header(msg["Subject"]) if isinstance(subject, bytes): # if it's a bytes, decode to str subject = subject.decode(encoding) # decode email sender From, encoding = decode_header(msg.get("From")) if isinstance(From, bytes): From = From.decode(encoding) print("Subject:", subject) print("From:", From) # if the email message is multipart if msg.is_multipart(): # iterate over email parts for part in msg.walk(): # extract content type of email content_type = part.get_content_type() content_disposition = str(part.get("Content-Disposition")) try: # get the email body body = part.get_payload(decode=True).decode() except: pass if content_type == "text/plain" and "attachment" not in content_disposition: # print text/plain emails and skip attachments print(body) elif "attachment" in content_disposition: # download attachment filename = part.get_filename() if filename: folder_name = clean(subject) if not os.path.isdir(folder_name): # make a folder for this email (named after the subject) os.mkdir(folder_name) filepath = os.path.join(folder_name, filename) # download attachment and save it open(filepath, "wb").write(part.get_payload(decode=True)) else: # extract content type of email content_type = msg.get_content_type() # get the email body body = msg.get_payload(decode=True).decode() if content_type == "text/plain": # print only text email parts print(body) if content_type == "text/html": # if it's HTML, create a new HTML file and open it in browser folder_name = clean(subject) if not os.path.isdir(folder_name): # make a folder for this email (named after the subject) os.mkdir(folder_name) filename = "index.html" filepath = os.path.join(folder_name, filename) # write the file open(filepath, "w").write(body) # open in the default browser webbrowser.open(filepath) print("="*100) # close the connection and logout imap.close() imap.logout()
Subject: Thanks for Subscribing to our Newsletter ! From: [email protected] ==================================================================================================== Subject: An email with a photo as an attachment From: Python Code <[email protected]> Get the photo now! ==================================================================================================== Subject: A Test message with attachment From: Python Code <[email protected]> There you have it! ====================================================================================================
So the code will only print
text/plain body messages, it will create a folder for each email, in which it contains the attachment and the HTML version of the email, it also opens the HTML email in your default browser for each email extracted that has the HTML content.
Going to my Gmail, I see the same emails that were printed in Python:
Awesome, I also notice the folders created for each email:
Each folder now has the HTML message (if available) and all the files attached with the email.
Awesome, now you can build your own email client using this recipe, for example, instead of opening each email on a new browser tab, you can build a GUI program which reads and parses HTML just like a regular browser, or maybe you want to send notifications whenever a new email is sent to you, the possibilities are endless !
A note though, we haven't covered everything that imaplib module offers, for example, you can search for emails and filter by the sender address, subject, sending date, and more using imap.search() method.
Here are other Python email tutorials:
Here is the documentation of modules used for this tutorial:
Finally, if you're a beginner and want to learn Python, I suggest you take Master Python in 5 Online Courses from University of Michigan, in which you'll learn a lot about Python, good luck!
Learn also: How to Handle Files in Python using OS Module.
Happy Coding ♥View Full Code