Python3, imaplib, expunge command used as per message in a loop over all messages in folder

Viewed 128

I have a bunch of functions to store all attachments from all mails in one imap folder. Attachments are json datasets for further processing. To avoid oubliettes after connection loss and re-connection I inserted an expunge command after each message in the loop. This leads to sporadic errors while processing an emailbody or better say: I can't read the body of the email resulting in [none] for the body. To solve the problem I placed the expunge command after the loop and inserted another expunge command before the loop to delete marked messages to prevent multiple processing.

Though I have my function working flawlessly maybe someone can tell me about the serverside behaviour of an expunge command ( can't say which imap-server is running on serverside, provider is ionos.de). I can't find related information in the RFC document. Maybe some kind of race condition.

This is the code that leads to errors:

def downloadAllAttachmentsInInbox( **args):

conf =args['conf']

m = connectImapServer( conf.imappoll.server, conf.imappoll.account, conf.imappoll.password)
resp, items = m.search( None, "(ALL)")
items = items[0].split()
for emailid in items:
    downloaAttachmentsInEmail( m =m, emailid =emailid, conf =conf)
    # Markiere Mail zum löschen
    if conf.imappoll.clearmb =="True":
        m.store( emailid, '+FLAGS', '\\Deleted')
        # Loesche markierte Mail(s)
        m.expunge()
# Schliesse Mailbox, logout aus Server
m.close()
m.logout()

And this is the working code:

def downloadAllAttachmentsInInbox( **args):

conf =args['conf']

m = connectImapServer( conf.imappoll.server, conf.imappoll.account, conf.imappoll.password)
# Loesche bereits zur Löschung markierte Mails vom Server vor Abruf aller Nachrichten
m.expunge()
resp, items = m.search( None, "(ALL)")
items = items[0].split()
for emailid in items:
    downloaAttachmentsInEmail( m =m, emailid =emailid, conf =conf)
    # Markiere Mail zum löschen
    if conf.imappoll.clearmb =="True":
        m.store( emailid, '+FLAGS', '\\Deleted')
# Loesche markierte Mail(s)
m.expunge()
# Schliesse Mailbox, logout aus Server
m.close()
m.logout()
1 Answers

If you use message sequence numbers, you may not use expunge, since it renumbers messages, making your search results out of date.

You have a couple options:

  • Use UIDs everywhere. m.uid(‘SEARCH’, ‘ALL’) and m.uid(‘FETCH’, …) and m.uid(‘STORE’, …). UIDs aren’t renumbered on expunge.
  • Don’t expunge, and search for UNDELETED instead, to ignore messages you’ve already marked deleted (eg, processed). m.search(‘UNDELETED’). Then expunge outside of the loop.
Related