python - Descargando mĂșltiples archivos adjuntos usando imaplib
email attachment (4)
¿Cómo puedo descargar varios archivos adjuntos de un solo correo usando imaplib ?
Digamos que tengo un correo electrónico y ese correo electrónico contiene 4 archivos adjuntos. ¿Cómo puedo descargar todos esos archivos adjuntos? El siguiente código solo descarga un archivo adjunto de un correo electrónico.
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'')
Para cualquier futuro viajero pitón. Aquí hay una clase que descarga cualquier archivo adjunto encontrado para un correo electrónico y lo guarda en una ubicación específica.
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)
Reelaboré el código, dividiéndolo en funciones. Uso PEEK
para no cambiar el estado de UNREAD de los mensajes de correo electrónico.
Estoy publicando mi opinión sobre el problema, similar a @John, pero solo uso funciones en lugar de clases:
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)
Su código parece correcto, excepto por la return
(¿quizás un error tipográfico?) Justo después de fp.close()
:
...
fp.write(part.get_payload(decode=True))
fp.close()
return HttpResponse(''check folder'')
Después de guardar el primer archivo adjunto, regresa de la función. Comente esa línea y vea si soluciona su problema.
* You can try following function to get mail attachment
def create_message_attachment(self,msg_str):
count = 1
body = ''''
content_id = ''''
for part in msg_str.walk():
file_name_gl = None
mptype = part.get_content_maintype()
file_name_gl = part.get_filename()
if mptype == "multipart":
continue
elif mptype == "text":
if not file_name_gl: continue
elif mptype == "image":
content_id = part.get(''Content-ID'')
if not file_name_gl:
file_name_gl = ''image_'' + str(count) + ''.'' + part.get_content_subtype()
count = count + 1
body = part.get_payload(decode = True)
if type(body) <> type(None) :
body = body.strip()
if body <> "":
body = base64.encodestring(body)