Search code examples
pythonpython-3.ximaplib

Python imaplib - get_filename() not working when attachment has UTF-8 characters


I have this function that downloads all attachments from a given email using imaplib

# Download all attachment files for a given email
def downloaAttachmentsInEmail(m, emailid, outputdir, markRead):
    resp, data = m.uid("FETCH", emailid, "(BODY.PEEK[])")
    email_body = data[0][1]
    mail = email.message_from_bytes(email_body)
    if mail.get_content_maintype() != 'multipart':
        return
    for part in mail.walk():
        if part.get_content_maintype() != 'multipart' and part.get('Content-Disposition') is not None:
            open(outputdir + '/' + part.get_filename(), 'wb').write(part.get_payload(decode=True)
    if(markRead):
        m.uid("STORE", emailid, "+FLAGS", "(\Seen)")

The problem is it doesn't work when I try to download a file that has UTF-8 characters in the file name. I get this error, which I guess is happening because part.get_filename() isn't reading the name correctly:

    OSError: [Errno 22] Invalid argument: './temp//=?UTF-8?B?QkQgUmVsYXTDs3JpbyAywqogRmFzZS5kb2M=?=\r\n\t=?UTF-8?B?eA==?='

What can I do to fix this?


Solution

  • I found a solution

    # Download all attachment files for a given email
    def downloaAttachmentsInEmail(m, emailid, outputdir, markRead):
        resp, data = m.uid("FETCH", emailid, "(BODY.PEEK[])")
        email_body = data[0][1]
        mail = email.message_from_bytes(email_body)
        if mail.get_content_maintype() != 'multipart':
            return
        for part in mail.walk():
            if part.get_content_maintype() != 'multipart' and part.get('Content-Disposition') is not None:
                filename, encoding = decode_header(part.get_filename())[0]
                if(encoding is None):
                    open(outputdir + '/' + filename, 'wb').write(part.get_payload(decode=True))
                else:
                    open(outputdir + '/' + filename.decode(encoding), 'wb').write(part.get_payload(decode=True))
        if(markRead):
            m.uid("STORE", emailid, "+FLAGS", "(\Seen)")**