Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Downloading multiple attachments using imaplib

How can I download multiple attachments from a single mail using imaplib?

Let's say I have an e-mail and that e-mail contains 4 attachments. How can I download all of those attachments? The code below only downloads a single attachment from an e-mail.

detach_dir = 'c:/downloads'
m = imaplib.IMAP4_SSL("imap.gmail.com")
m.login('[email protected]','3323434')
m.select("[Gmail]/All Mail")

resp, items = m.search(None, "(UNSEEN)")
items = items[0].split()

for emailid in items:
    resp, data = m.fetch(emailid, "(RFC822)") 
    email_body = data[0][1] 
    mail = email.message_from_string(email_body) 
    temp = m.store(emailid,'+FLAGS', '\\Seen')
    m.expunge()

    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()
            return HttpResponse('check folder')
like image 247
harde Avatar asked Jun 03 '11 10:06

harde


People also ask

How do I download email attachments in bulk?

You need to select the messages from which you wish to download the attachments in bulk all at one place. Go to the tab Message and click on Attachments. Next, tap on Download all Attachments. You need to select the directory location to save all your attachments.

How do I download attachments from server?

Download the attached file. Click on the thumbnail icon for the attached file. Then right-click and select the "Save" option. You also can download the attachment by right-clicking it and selecting "Download."

How do you check if an email has an attachment Python?

In general, you can try analyzing content-type header. If it's multipart/mixed, most likely the message contains an attachment.


4 Answers

For any future python travellers. Here is a class that downloads any attachment found for an email and saves it to a specific location.

import email import imaplib import os  class FetchEmail():      connection = None     error = None      def __init__(self, mail_server, username, password):         self.connection = imaplib.IMAP4_SSL(mail_server)         self.connection.login(username, password)         self.connection.select(readonly=False) # so we can mark mails as read      def close_connection(self):         """         Close the connection to the IMAP server         """         self.connection.close()      def save_attachment(self, msg, download_folder="/tmp"):         """         Given a message, save its attachments to the specified         download folder (default is /tmp)          return: file path to attachment         """         att_path = "No attachment found."         for part in msg.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(download_folder, filename)              if not os.path.isfile(att_path):                 fp = open(att_path, 'wb')                 fp.write(part.get_payload(decode=True))                 fp.close()         return att_path      def fetch_unread_messages(self):         """         Retrieve unread messages         """         emails = []         (result, messages) = self.connection.search(None, 'UnSeen')         if result == "OK":             for message in messages[0].split(' '):                 try:                      ret, data = self.connection.fetch(message,'(RFC822)')                 except:                     print "No new emails to read."                     self.close_connection()                     exit()                  msg = email.message_from_bytes(data[0][1])                 if isinstance(msg, str) == False:                     emails.append(msg)                 response, data = self.connection.store(message, '+FLAGS','\\Seen')              return emails          self.error = "Failed to retreive emails."         return emails      def parse_email_address(self, email_address):         """         Helper function to parse out the email address from the message          return: tuple (name, address). Eg. ('John Doe', '[email protected]')         """         return email.utils.parseaddr(email_address) 
like image 88
John Paul Hayes Avatar answered Sep 20 '22 15:09

John Paul Hayes


I reworked the code, breaking it up into functions. I use PEEK so I don't change the UNREAD status of the email messages.

I'm posting my take on the problem, similar to @John, but I use only functions instead of classes:

import imaplib import email  # Connect to an IMAP server def connect(server, user, password):     m = imaplib.IMAP4_SSL(server)     m.login(user, password)     m.select()     return m  # Download all attachment files for a given email def downloaAttachmentsInEmail(m, emailid, outputdir):     resp, data = m.fetch(emailid, "(BODY.PEEK[])")     email_body = data[0][1]     mail = email.message_from_string(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))  # Download all the attachment files for all emails in the inbox. def downloadAllAttachmentsInInbox(server, user, password, outputdir):     m = connect(server, user, password)     resp, items = m.search(None, "(ALL)")     items = items[0].split()     for emailid in items:         downloaAttachmentsInEmail(m, emailid, outputdir) 
like image 27
sashoalm Avatar answered Sep 20 '22 15:09

sashoalm


You code appears okay except for the return (perhaps a typo?) right after the fp.close():

...
fp.write(part.get_payload(decode=True))
fp.close()
return HttpResponse('check folder')

After saving the first attachment it returns from the function. Comment out that line and see if it fixes your issue.

like image 33
samplebias Avatar answered Sep 20 '22 15:09

samplebias


You may use imap_tools package: https://pypi.org/project/imap-tools/

from imap_tools import MailBox
with MailBox('imap.mail.com').login('[email protected]', 'password', 'INBOX') as mailbox:
    for message in mailbox.fetch():
        for att in message.attachments:  # list: [Attachment objects]
            att.filename         # str: 'cat.jpg'
            att.content_type     # str: 'image/jpeg'
            att.payload          # bytes: b'\xff\xd8\xff\xe0\'
like image 43
Vladimir Avatar answered Sep 22 '22 15:09

Vladimir