What is an elegant way of searching only for new emails in python?

101 Views Asked by At

I am using imaplib to access emails for a Python script. I want to search for all emails received after the last time the script was run.

mail.search(None,'(FROM "[email protected]" SUBJECT "xyz" SINCE {last_timestamp})')

Unfortunately search ignores the time and only considers the date. Thus some old emails are retrieved if they were received on the same day as last_timestamp even though they are prior to the exact time.

As a workaround, I store email IDs and remove old ones from the search results. I'm wondering if there is a more elegant solution.

2

There are 2 best solutions below

0
Linda Lawton - DaImTo On

Try searching for unseen

# Select an email folder
inbox = box["INBOX"]

# Search and process messages
for msg in inbox.search(unseen=True):
0
Francesco On

You could use the fetch method to retrieve the INTERNALDATE of each email and then filter them based on the exact time.

something like this:

import imaplib
import email
from datetime import datetime

# Connect to your mailbox
imap_server = 'imap.example.com'
username = 'your_username'
password = 'your_password'
mailbox = 'INBOX'

imap = imaplib.IMAP4_SSL(imap_server)
imap.login(username, password)
imap.select(mailbox)

# Define the search criteria
from_email = '[email protected]'
subject = 'xyz'
last_timestamp = '2023-08-22 12:00:00'  # Replace with your last timestamp

# Search for emails based on the criteria
search_criteria = f'(FROM "{from_email}" SUBJECT "{subject}" SINCE "{last_timestamp}")'
status, email_ids = imap.search(None, search_criteria)

if status == 'OK':
    email_id_list = email_ids[0].split()
    new_emails = []

    # Iterate through the email IDs and fetch the INTERNALDATE
    for email_id in email_id_list:
        status, email_data = imap.fetch(email_id, '(INTERNALDATE)')
        if status == 'OK':
            # Parse the INTERNALDATE and convert it to a datetime object
            internal_date_str = email_data[0].split()[1].decode('utf-8')
            internal_date = datetime.strptime(internal_date_str, '%d-%b-%Y %H:%M:%S %z')

            # Compare the INTERNALDATE with the last timestamp
            if internal_date > datetime.strptime(last_timestamp, '%Y-%m-%d %H:%M:%S'):
                new_emails.append(email_id.decode('utf-8'))

    # Now, new_emails contains the email IDs of emails received after the last timestamp
    print("New email IDs:", new_emails)

imap.logout()

note that INTERNALDATE may be in a different time zone, so make sure to adjust your timestamp