Search code examples
python-2.7imapemail-attachments

Python IMAP locate emails with attachments in INBOX and move them to a folder


I'm trying to check my inbox for emails with attachments.

If I find some, I want to copy all attachments to "c:\temp" and then move those emails into the "INBOX/imported" folder.

The script below successfully identifies mails with attachments and copies the content to the directory. However moving the processed emails does not work.

At first attempts, the wrong mails were moved.

I moved all mails back to the inbox and now no mails will move.

On both the COPY and STORE commands the mailserver returns OK. But when I check the mail account, all mails are still in the inbox.

Any hints?

import imaplib
import re
import email 
import os

from email.parser import HeaderParser

def connect():
    imap = imaplib.IMAP4_SSL("my server")
    imap.login('<login>','<password>')
    return imap



if __name__ == '__main__':
    imap = connect()

    # List all mailboxes
    print(imap.list())

    imap.select(mailbox = 'INBOX', readonly = False)
    resp, items = imap.search(None, 'All')
    email_ids  = items[0].split()

    detach_dir = 'c:/temp/'

    for msg_uid in email_ids:

        print('message ' + msg_uid)
        resp, data = imap.fetch(msg_uid, "(RFC822)") 
        email_body = data[0][1] 
        mail = email.message_from_string(email_body) 
        if mail.get_content_maintype() != 'multipart':
           continue
        print "["+mail["From"]+"] :" + mail["Subject"]

        for part in mail.walk():
            if part.get_content_maintype() == 'multipart':
                continue
            if part.get('Content-Disposition') is None:
                continue
            filename = part.get_filename()
            att_path = os.path.join(detach_dir, filename)
            if not os.path.isfile(att_path) :
                fp = open(att_path, 'wb')
                fp.write(part.get_payload(decode=True))
                fp.close()

        print('COPY ' + msg_uid)

        apply_lbl_msg = imap.uid('COPY', msg_uid, 'INBOX/imported')
        print(apply_lbl_msg)
        if apply_lbl_msg[0] == 'OK':
        mov, data = imap.uid('STORE', msg_uid , '+FLAGS', '(\Deleted)')
            print('delete ' + msg_uid)
            print(mov)
            print(data)
            imap.expunge()


    imap.close() # close the mailbox
    imap.logout()

Solution

  • Max's idea was correct:

     resp, items = imap.uid("search",None, 'All')
    

    return the UIDs, when fetched as

    resp, data = imap.uid('fetch',msg_uid, "(RFC822)") 
    

    the fetch works and it's possible to move the mails by UID