Obtén el nombre del archivo adjunto de Gmail sin descargarlo

Estoy tratando de obtener todos los mensajes de una cuenta de Gmail que pueden contener algunos archivos adjuntos grandes (alrededor de 30 MB). Solo necesito los nombres, no los archivos completos. Encontré un fragmento de código para recibir un mensaje y el nombre del archivo adjunto, pero descarga el archivo y luego lee su nombre:

import imaplib, email #log in and select the inbox mail = imaplib.IMAP4_SSL('imap.gmail.com') mail.login('username', 'password') mail.select('inbox') #get uids of all messages result, data = mail.uid('search', None, 'ALL') uids = data[0].split() #read the lastest message result, data = mail.uid('fetch', uids[-1], '(RFC822)') m = email.message_from_string(data[0][1]) if m.get_content_maintype() == 'multipart': #multipart messages only for part in m.walk(): #find the attachment part if part.get_content_maintype() == 'multipart': continue if part.get('Content-Disposition') is None: continue #save the attachment in the program directory filename = part.get_filename() fp = open(filename, 'wb') fp.write(part.get_payload(decode=True)) fp.close() print '%s saved!' % filename 

Tengo que hacer esto una vez por minuto, por lo que no puedo descargar cientos de MB de datos. Soy un novato en las secuencias de comandos web, ¿podría alguien ayudarme? Realmente no necesito usar imaplib, cualquier lib de python estará bien para mí.

Atentamente

En lugar de buscar RFC822 , que es el contenido completo, puede especificar BODYSTRUCTURE .

La estructura de datos resultante de imaplib es bastante confusa, pero debería poder encontrar el nombre del archivo, el tipo de contenido y los tamaños de cada parte del mensaje sin descargar todo el contenido.

Si sabe algo sobre el nombre del archivo, puede usar las extensiones de gmail X-GM-RAW para el comando imap SEARCH . Estas extensiones le permiten utilizar cualquier consulta de búsqueda avanzada de gmail para filtrar los mensajes. De esta manera, puede restringir las descargas a los mensajes coincidentes, o excluir algunos mensajes que no desea.

 mail.uid('search', None, 'X-GM-RAW', 'has:attachment filename:pdf in:inbox -label:parsed')) 

La búsqueda anterior de mensajes con archivos adjuntos PDF en la CAJA NO está etiquetada como “analizada”.

Algunos consejos pro:

  • etiqueta los mensajes que ya has analizado, por lo que no necesitas recuperarlos nuevamente (la etiqueta -label: parsed filter en el ejemplo anterior)
  • siempre use la versión de uid en lugar de los identificadores secuenciales estándar (ya lo está haciendo)
  • desafortunadamente, MIME está desordenado: hay muchos clientes que hacen cosas raras (o simplemente erróneas). Puedes intentar descargar y analizar solo los encabezados, pero ¿vale la pena?

[editar]

Si etiqueta un mensaje después de analizarlo, puede omitir los mensajes que ya ha analizado. Esto debería ser lo suficientemente razonable para controlar su buzón de correo de clase.

Tal vez usted vive en un rincón del mundo donde el ancho de banda de Internet es más caro que el tiempo de progtwigción; en este caso, puede obtener solo los encabezados y buscar el archivo adjunto “Content-disposition” == “; filename = somefilename.ext”.

Un FETCH del elemento de datos del mensaje RFC822 es funcionalmente equivalente a BODY[] . IMAP4 es compatible con otros elementos de datos de mensajes, enumerados en la sección 6.4.5 de RFC 3501 .

Intente solicitar un conjunto diferente de elementos de datos de mensajes para obtener solo la información que necesita. Por ejemplo, puede probar RFC822.HEADER o tal vez BODY.PEEK[MIME] .

Pregunta antigua, pero solo quería compartir la solución que se me ocurrió hoy. Busca todos los correos electrónicos con archivos adjuntos y genera el uid, el remitente, el asunto y una lista formateada de archivos adjuntos. Código relevante editado para mostrar cómo formatear BODISTRUCTURA:

  data = mailobj.uid('fetch', mail_uid, '(BODYSTRUCTURE)')[1] struct = data[0].split() list = [] #holds list of attachment filenames for j, k in enumerate(struct): if k == '("FILENAME"': count = 1 val = struct[j + count] while val[-3] != '"': count += 1 val += " " + struct[j + count] list.append(val[1:-3]) elif k == '"FILENAME"': count = 1 val = struct[j + count] while val[-1] != '"': count += 1 val += " " + struct[j + count] list.append(val[1:-1]) 

También lo he publicado en GitHub .