2010-08-20 93 views

Respuesta

33

No hay un comando de movimiento explícito para IMAP. Tendrá que ejecutar un COPY seguido de un STORE (con un indicador adecuado para indicar la eliminación) y finalmente expunge. El ejemplo que se muestra a continuación funcionó para mover mensajes de una etiqueta a la otra. Sin embargo, es probable que desee agregar más verificación de errores.

import imaplib, getpass, re 
pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)') 

def connect(email): 
    imap = imaplib.IMAP4_SSL("imap.gmail.com") 
    password = getpass.getpass("Enter your password: ") 
    imap.login(email, password) 
    return imap 

def disconnect(imap): 
    imap.logout() 

def parse_uid(data): 
    match = pattern_uid.match(data) 
    return match.group('uid') 

if __name__ == '__main__': 
    imap = connect('<your mail id>') 
    imap.select(mailbox = '<source folder>', readonly = False) 
    resp, items = imap.search(None, 'All') 
    email_ids = items[0].split() 
    latest_email_id = email_ids[-1] # Assuming that you are moving the latest email. 

    resp, data = imap.fetch(latest_email_id, "(UID)") 
    msg_uid = parse_uid(data[0]) 

    result = imap.uid('COPY', msg_uid, '<destination folder>') 

    if result[0] == 'OK': 
     mov, data = imap.uid('STORE', msg_uid , '+FLAGS', '(\Deleted)') 
     imap.expunge() 

    disconnect(imap) 
+2

¿Alguna idea de mover más de un mensaje? ¿tiene que ejecutar otra búsqueda y tomar el último mensaje con email_ids [-1]? – ewalk

+3

Gmail IMAP * automáticamente * hace el '\ Deleted' /' EXPUNGE' cuando 'COPY' envía un mensaje a '[Gmail]/Trash'. – dkarp

+0

@dkarp gracias por la información que ha proporcionado. Estaba intentando esto desde la última semana. –

4

Supongo que uno tiene un uid del correo electrónico que se va a mover.

import imaplib 
obj = imaplib.IMAP4_SSL('imap.gmail.com', 993) 
obj.login('username', 'password') 
obj.select(src_folder_name) 
apply_lbl_msg = obj.uid('COPY', msg_uid, desti_folder_name) 
if apply_lbl_msg[0] == 'OK': 
    mov, data = obj.uid('STORE', msg_uid , '+FLAGS', '(\Deleted)') 
    obj.expunge() 
4

En cuanto a Gmail, en función de su api working with labels, lo único que puedes hacer es la adición de etiquetas dest y eliminar la etiqueta src:

import imaplib 
obj = imaplib.IMAP4_SSL('imap.gmail.com', 993) 
obj.login('username', 'password') 
obj.select(src_folder_name) 
typ, data = obj.uid('STORE', msg_uid, '+X-GM-LABELS', desti_folder_name) 
typ, data = obj.uid('STORE', msg_uid, '-X-GM-LABELS', src_folder_name) 
+0

Esto no funcionó para mí. Agregó la etiqueta desti_folder_name, pero no eliminó la etiqueta src_folder_name. La solución anterior de Manoj Govindan sí funcionó para mí, sin embargo. – mernst

+0

Puedo confirmar lo mismo, pero ¿por qué la eliminación no funciona? ¿Cuál es la solución correcta? – sorin

+0

@soy esto funciona para mí, es posible que esté haciendo algo mal. Lo hice ahora siguiendo todos los pasos por línea ... – scraplesh

3

Ninguna de las soluciones anteriores trabajó para mí. No pude eliminar un mensaje de la carpeta seleccionada y no pude eliminar la etiqueta de la carpeta cuando la etiqueta era la carpeta seleccionada. Aquí está lo que terminó trabajando para mí:

import email, getpass, imaplib, os, sys, re 

user = "[email protected]" 
pwd = "password" #getpass.getpass("Enter your password: ") 

m = imaplib.IMAP4_SSL("imap.gmail.com") 
m.login(user,pwd) 

from_folder = "Notes" 
to_folder = "food" 

m.select(from_folder, readonly = False) 

response, emailids = imap.search(None, 'All') 
assert response == 'OK' 

emailids = emailids[0].split() 

errors = [] 
labeled = [] 
for emailid in emailids: 
    result = m.fetch(emailid, '(X-GM-MSGID)') 
    if result[0] != 'OK': 
     errors.append(emailid) 
     continue 

    gm_msgid = re.findall(r"X-GM-MSGID (\d+)", result[1][0])[0] 

    result = m.store(emailid, '+X-GM-LABELS', to_folder) 

    if result[0] != 'OK': 
     errors.append(emailid) 
     continue 

    labeled.append(gm_msgid) 

m.close() 
m.select(to_folder, readonly = False) 

errors2 = [] 

for gm_msgid in labeled: 
    result = m.search(None, '(X-GM-MSGID "%s")' % gm_msgid) 

    if result[0] != 'OK': 
     errors2.append(gm_msgid) 
     continue 

    emailid = result[1][0] 
    result = m.store(emailid, '-X-GM-LABELS', from_folder) 

    if result[0] != 'OK': 
     errors2.append(gm_msgid) 
     continue 

m.close() 
m.logout() 

if errors: print >>sys.stderr, len(errors), "failed to add label", to_folder 
if errors2: print >>sys.stderr, len(errors2), "failed to remove label", from_folder 
0

Sé que esta es una pregunta muy antigua, pero de cualquier manera. La solución propuesta por Manoj Govindan probablemente funciona a la perfección (no lo he probado pero parece que sí. El problema que encuentro y tuve que resolver es cómo copiar/mover más de un correo electrónico !!!

Así que vine con la solución, tal vez alguien más en el futuro podría tener el mismo problema.

Los pasos son simples, me conecto a mi cuenta de correo electrónico (GMAIL) elegir carpeta para procesar (por ejemplo, INBOX) buscar todos los líquidos, en lugar de correo electrónico (s) número de lista. Este es un punto crucial para notar aquí. Si buscamos la lista de correos electrónicos y luego procesamos la lista, tendríamos un problema. Cuando movemos un correo electrónico, el proceso es simple (copiar en el destino) carpeta y elimine el correo electrónico de cada ubicación actual). El problema aparece si tiene una lista de correos electrónicos, p. 4 correos electrónicos dentro de la bandeja de entrada y procesamos el 2º correo electrónico dentro de la lista, luego los números 3 y 4 son diferentes, no son los correos electrónicos que pensamos que serían, lo que generará un error porque el número 4 de la lista no lo hará existe ya que la lista se movió una posición hacia abajo porque la posición 2 estaba vacía.

Así que la única solución posible a este problema era usar UID. Que son números únicos para cada correo electrónico. Entonces, no importa cómo cambie el correo electrónico, este número se vinculará con el correo electrónico.

Por lo tanto, en el ejemplo siguiente, busco los UID en el primer paso, compruebo si la carpeta está vacía, no hay punto de procesamiento de la carpeta, más itera para todos los correos electrónicos encontrados en la carpeta. A continuación, busque cada Encabezado de correo electrónico. Los encabezados nos ayudarán a buscar el tema y comparar el tema del correo electrónico con el que estamos buscando. Si el asunto coincide, continúe copiando y eliminando el correo electrónico. Entonces has terminado. Simple como eso.

#!/usr/bin/env python 

import email 
import pprint 
import imaplib 

__author__ = 'author' 


def initialization_process(user_name, user_password, folder): 
    imap4 = imaplib.IMAP4_SSL('imap.gmail.com') # Connects over an SSL encrypted socket 
    imap4.login(user_name, user_password) 
    imap4.list() # List of "folders" aka labels in gmail 
    imap4.select(folder) # Default INBOX folder alternative select('FOLDER') 
    return imap4 


def logout_process(imap4): 
    imap4.close() 
    imap4.logout() 
    return 


def main(user_email, user_pass, scan_folder, subject_match, destination_folder): 
    try: 
     imap4 = initialization_process(user_email, user_pass, scan_folder) 
     result, items = imap4.uid('search', None, "ALL") # search and return uids 
     dictionary = {} 
     if items == ['']: 
      dictionary[scan_folder] = 'Is Empty' 
     else: 
      for uid in items[0].split(): # Each uid is a space separated string 
       dictionary[uid] = {'MESSAGE BODY': None, 'BOOKING': None, 'SUBJECT': None, 'RESULT': None} 
       result, header = imap4.uid('fetch', uid, '(UID BODY[HEADER])') 
       if result != 'OK': 
        raise Exception('Can not retrieve "Header" from EMAIL: {}'.format(uid)) 
       subject = email.message_from_string(header[0][1]) 
       subject = subject['Subject'] 
       if subject is None: 
        dictionary[uid]['SUBJECT'] = '(no subject)' 
       else: 
        dictionary[uid]['SUBJECT'] = subject 
       if subject_match in dictionary[uid]['SUBJECT']: 
        result, body = imap4.uid('fetch', uid, '(UID BODY[TEXT])') 
        if result != 'OK': 
         raise Exception('Can not retrieve "Body" from EMAIL: {}'.format(uid)) 
        dictionary[uid]['MESSAGE BODY'] = body[0][1] 
        list_body = dictionary[uid]['MESSAGE BODY'].splitlines() 
        result, copy = imap4.uid('COPY', uid, destination_folder) 
        if result == 'OK': 
         dictionary[uid]['RESULT'] = 'COPIED' 
         result, delete = imap4.uid('STORE', uid, '+FLAGS', '(\Deleted)') 
         imap4.expunge() 
         if result == 'OK': 
          dictionary[uid]['RESULT'] = 'COPIED/DELETED' 
         elif result != 'OK': 
          dictionary[uid]['RESULT'] = 'ERROR' 
          continue 
        elif result != 'OK': 
         dictionary[uid]['RESULT'] = 'ERROR' 
         continue 
       else: 
        print "Do something with not matching emails" 
        # do something else instead of copy 
      dictionary = {scan_folder: dictionary} 
    except imaplib.IMAP4.error as e: 
     print("Error, {}".format(e)) 
    except Exception as e: 
     print("Error, {}".format(e)) 
    finally: 
     logout_process(imap4) 
     return dictionary 

if __name__ == "__main__": 
    username = '[email protected]' 
    password = 'examplePassword' 
    main_dictionary = main(username, password, 'INBOX', 'BOKNING', 'TMP_FOLDER') 
    pprint.pprint(main_dictionary) 
    exit(0) 

información útil con respecto imaplib Python — imaplib IMAP example with Gmail y la imaplib documentation.

Cuestiones relacionadas