Getting n most recent emails using IMAP and Python
Asked Answered
E

6

16

I'm looking to return the n (most likely 10) most recent emails from an email accounts inbox using IMAP.

So far I've cobbled together:

import imaplib
from email.parser import HeaderParser

M = imaplib.IMAP4_SSL('my.server')
user = 'username'
password = 'password'
M.login(user, password)
M.search(None, 'ALL')
for i in range (1,10):
    data = M.fetch(i, '(BODY[HEADER])')
    header_data = data[1][0][1]
    parser = HeaderParser()
    msg = parser.parsestr(header_data)
    print msg['subject']

This is returning email headers fine, but it seems to be a semi-random collection of emails that it gets, not the 10 most recent.

If it helps, I'm connecting to an Exchange 2010 server. Other approaches also welcome, IMAP just seemed the most appropriate given that I only wanted to read the emails not send any.

Euphemize answered 12/4, 2011 at 8:58 Comment(0)
Z
19

The sort command is available, but it is not guaranteed to be supported by the IMAP server. For example, Gmail does not support the SORT command.

To try the sort command, you would replace:
M.search(None, 'ALL')
with
M.sort(search_critera, 'UTF-8', 'ALL')

Then search_criteria would be a string like:

search_criteria = 'DATE' #Ascending, most recent email last
search_criteria = 'REVERSE DATE' #Descending, most recent email first

search_criteria = '[REVERSE] sort-key' #format for sorting

According to RFC5256 these are valid sort-key's:
"ARRIVAL" / "CC" / "DATE" / "FROM" / "SIZE" / "SUBJECT" / "TO"

Notes:
1. charset is required, try US-ASCII or UTF-8 all others are not required to be supported by the IMAP server
2. search critera is also required. The ALL command is a valid one, but there are many. See more at http://www.networksorcery.com/enp/rfc/rfc3501.txt

The world of IMAP is wild and crazy. Good luck

Zulmazulu answered 12/4, 2011 at 20:22 Comment(4)
Using the sort method with any of the sort-keys returns: imaplib.error: SORT command error: BAD ['Command Error. 12'], I can't work out if this is because Outlook doesn't support the SORT call/method/argument, or because I'm using IMAPlibs sort method the wrong way.Euphemize
Using the third party library IMAPClient, trying the sort method raises an exception telling me that the server doesn't support the sort method.Euphemize
Yea, sorry to hear that. Like I said, the sort method is not a requirement according to the specs. I don't have access to an Exchange or I would have tried it for you.Zulmazulu
GMAIL imap for example doesn't support the sort command ... I'm in that case, it seems you need to get every emails, and sort it by yourself.Monica
C
4
# get recent one email
from imap_tools import MailBox
with MailBox('imap.mail.com').login('[email protected]', 'password', 'INBOX') as mailbox:
   for msg in mailbox.fetch(limit=1, reverse=True):
       print(msg.date_str, msg.subject)

https://github.com/ikvk/imap_tools

Carcassonne answered 11/4, 2020 at 11:21 Comment(0)
C
3

This is the code to get the emailFrom, emailSubject, emailDate, emailContent etc..

import imaplib, email, os
user = "[email protected]"
password = "pass"
imap_url = "imap.gmail.com"
connection = imaplib.IMAP4_SSL(imap_url)
connection.login(user, password)
result, data = connection.uid('search', None, "ALL")
if result == 'OK':
    for num in data[0].split():
        result, data = connection.uid('fetch', num, '(RFC822)')
        if result == 'OK':
            email_message = email.message_from_bytes(data[0][1])
            print('From:' + email_message['From'])
            print('To:' + email_message['To'])
            print('Date:' + email_message['Date'])
            print('Subject:' + str(email_message['Subject']))
            print('Content:' + str(email_message.get_payload()[0]))
connection.close()
connection.logout()        
Cracksman answered 25/6, 2018 at 14:41 Comment(0)
V
0

this is work for me~

import imaplib
from email.parser import HeaderParser
M = imaplib.IMAP4_SSL('my.server')
user = 'username'
password = 'password'
M.login(user, password)
(retcode, messages) =M.search(None, 'ALL')
 news_mail = get_mostnew_email(messages)
for i in news_mail :
    data = M.fetch(i, '(BODY[HEADER])')
    header_data = data[1][0][1]
    parser = HeaderParser()
    msg = parser.parsestr(header_data)
    print msg['subject']

and this is get the newer email function :

def get_mostnew_email(messages):
    """
    Getting in most recent emails using IMAP and Python
    :param messages:
    :return:
    """
    ids = messages[0]  # data is a list.
    id_list = ids.split()  # ids is a space separated string
    #latest_ten_email_id = id_list  # get all
    latest_ten_email_id = id_list[-10:]  # get the latest 10
    keys = map(int, latest_ten_email_id)
    news_keys = sorted(keys, reverse=True)
    str_keys = [str(e) for e in news_keys]
    return  str_keys
Vikkivikky answered 5/9, 2017 at 6:37 Comment(1)
Wall of code and no explanation. Can you please add some explanation how the code is working so that beginners may get a better understanding.Fellowship
W
0

Workaround for Gmail. Since the The IMAP.sort('DATE','UTF-8','ALL') does not work for gmail ,we can insert the values and date into a list and sort the list in reverse order of date. Can check for the first n-mails using a counter. This method will take a few minutes longer if there are hundreds of mails.

    M.login(user,password)
    rv,data= M.search(None,'ALL')
    if rv=='OK':
        msg_list=[]
        for num in date[0].split():
            rv,data=M.fetch(num,'(RFC822)')
            if rv=='OK':
                msg_object={}
                msg_object_copy={}
                msg=email.message_from_bytes(data[0][1])
                msg_date=""
                for val in msg['Date'].split(' '):
                    if(len(val)==1):
                        val="0"+val
                    # to pad the single date with 0
                    msg_date=msg_date+val+" "
                msg_date=msg_date[:-1]
              # to remove the last space
                msg_object['date']= datetime.datetime.strptime(msg_date,"%a, %d %b %Y %H:%M:%S %z")
            # to convert string to date time object for sorting the list
                msg_object['msg']=msg
                msg_object_copy=msg_object.copy()
                msg_list.append(msg_object_copy)
        msg_list.sort(reverse=True,key=lambda r:r['date'])
# sorts by datetime so latest mails are parsed first
        count=0
        for msg_obj in msg_list:
            count=count+1
            if count==n:
                break
            msg=msg_obj['msg']
        # do things with the message
Wortman answered 23/5, 2020 at 8:43 Comment(0)
H
0

To get the latest mail:

This will return all the mail numbers contained inside the 2nd return value which is a list containing a bytes object:

imap.search(None, "ALL")[1][0]

This will split the bytes object of which the last element can be taken by accessing the negative index:

imap.search(None, "ALL")[1][0].split()[-1]

You may use the mail number to access the corresponding mail.

Haitian answered 19/5, 2022 at 9:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.