Skip to Content
Course content

279: Reading Emails with imaplib

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was tasked with automating a data pipeline for a client who relied on a legacy mainframe system. The mainframe couldn't talk to a modern API, but it could send emails. Every morning at 4:00 AM, it would blast out a series of reports as CSV attachments. My job was to grab those files and load them into a database before the business analysts started their day. I spent a whole afternoon trying to find a "modern" library for this, only to realize that the old-school imaplib is still the industry standard for this kind of work. It's a bit clunky, but it's reliable.

Talking to the Mail Server

To get started, you'll need to establish a secure connection. We use imaplib.IMAP4_SSL because, frankly, sending your email password over an unencrypted connection in the 21st century is a disaster waiting to happen. Once connected, you log in and select the folder you want to browse—usually the "INBOX".

The trickiest part is often the search. IMAP uses a specific search syntax that feels more like a query language than Python. If you want to find emails from a specific sender or with a specific keyword in the subject, you pass those criteria into the search() method. Keep in mind that search() returns a list of message IDs, not the emails themselves. You're essentially getting a list of "addresses" for the messages you actually want to read.

import imaplib
import email

# Connect to the server
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('your_email@gmail.com', 'your_app_password')
mail.select('inbox')

# Search for emails from a specific report bot
status, data = mail.search(None, '(FROM "reports@company.com" SUBJECT "Daily Summary")')
mail_ids = data[0].split()

if mail_ids:
    # Get the latest email ID
    latest_id = mail_ids[-1]
    status, data = mail.fetch(latest_id, '(RFC822)')
    raw_email = data[0][1]
else:
    print("No matching emails found.")

Parsing the Multipart Mess

Here is where most developers get stuck. imaplib fetches the email as a raw byte string. If you print raw_email from the code above, it looks like a nightmare of headers, boundary markers, and encoded text. To make sense of this, we hand that raw data over to the email module.

Emails are often "multipart," meaning they contain a plain text version, an HTML version, and potentially attachments. I always recommend using the walk() method. This allows you to iterate through every part of the email and check the get_content_type(). If you're looking for the body of the message, you're usually hunting for text/plain. If you need a file, you're looking for application/octet-stream or similar.

# Convert raw bytes to a Message object
msg = email.message_from_bytes(raw_email)

# Extract basic headers
print(f"From: {msg['From']}")
print(f"Subject: {msg['Subject']}")

# Iterate through the email parts to find the body
for part in msg.walk():
    if part.get_content_type() == 'text/plain':
        body = part.get_payload(decode=True).decode()
        print(f"Body: {body}")
    elif part.get_content_maintype() == 'multipart':
        continue
    elif part.get_filename():
        print(f"Found attachment: {part.get_filename()}")

One quick word of advice: if you're using Gmail or Outlook, you can't just use your regular password. You'll need to generate an "App Password" in your account settings. I've wasted an hour of my life fighting "Authentication Failed" errors only to realize my two-factor authentication was blocking the script. Save yourself that headache.




📋 Practical Task

Project: Automated Invoice Subject Scraper

You have been asked to build a tool that audits an inbox for incoming invoices. Your goal is to create a script that connects to an IMAP server and identifies all emails that have the word "Invoice" in the subject line.

Requirements:

  • Connect to your email provider using imaplib.IMAP4_SSL.
  • Search the "INBOX" for all messages where the subject contains "Invoice".
  • For every matching email found, print the Sender's Email Address and the Date the email was sent.
  • Ensure the script handles the case where no matching emails are found without crashing.

Note: Use an App Password if your provider requires two-factor authentication.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.