Déplacer un e-mail dans GMail avec Python et imaplib

je veux pouvoir déplacer un e-mail dans GMail de la boîte de réception vers un autre dossier en utilisant Python. J'utilise imaplib et je ne sais pas comment le faire.

22
demandé sur Manoj Govindan 2010-08-20 07:13:42

5 réponses

il n'y a pas de commande explicite de déplacement pour IMAP. Vous devez exécuter un COPY suivi de STORE (avec un drapeau approprié pour indiquer la suppression) et enfin expunge. L'exemple ci-dessous a fonctionné pour déplacer les messages d'une étiquette à l'autre. Vous voudrez probablement ajouter plus de vérification d'erreur.

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)
36
répondu Manoj Govindan 2010-08-20 07:04:45

Comme pour Gmail, basé sur son api travaille avec des étiquettes, la seule chose à faire pour vous est d'ajouter dest étiquette et la suppression src étiquette:

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)
5
répondu scraplesh 2011-09-16 05:22:12

je suppose qu'on a un uid de l'email qui va être déplacé.

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
répondu Avadhesh 2014-07-25 00:38:37

Aucune des solutions précédentes a fonctionné pour moi. J'ai été incapable de supprimer un message dans le dossier sélectionné, et impossible de supprimer l'étiquette pour le dossier lorsque l'étiquette a été le dossier sélectionné. Voici ce qui a fini par marcher pour moi:

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

user = "user@example.com"
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
3
répondu Neal Young 2013-01-07 04:03:55

je sais que c'est une très vieille question, mais de toute manière. La solution proposée par Manoj Govindan fonctionne probablement parfaitement (Je ne l'ai pas testé mais il ressemble à lui. Le problème que je rencontre et que je devais résoudre est comment copier / déplacer plus d'un e-mail!!!

alors j'ai trouvé une solution, peut-être que quelqu'un d'autre dans le futur pourrait avoir le même problème.

les étapes sont simples, je me connecte à mon compte Email (GMAIL) choisir dossier à traiter (par exemple BOÎTE de réception) va chercher tous les uid, au lieu de la messagerie électronique(s) numéro de la liste. C'est un point crucial à noter ici. Si nous récupérions le nombre d'e-mails de la liste et que nous traitions ensuite la liste, nous finirions par avoir un problème. Lorsque nous déplaçons un e-mail, le processus est simple (copier dans le dossier de destination et supprimer l'e-mail de chaque emplacement actuel). Le problème apparaît si vous avez une liste d'e-mails par exemple 4 e-mails dans la boîte de réception et nous traitons le 2ème e-mail dans la liste alors les numéros 3 et 4 sont différents, ils ne sont pas les e-mails que nous pensions qu'ils seraient, ce qui résultera en une erreur parce que l'article de la liste Numéro 4, il n'existera pas puisque la liste a déplacé une position vers le bas parce que 2 position était vide.

donc la seule solution possible à ce problème était d'utiliser des uid. Qui sont des numéros uniques pour chaque e-mail. Donc, peu importe comment le courriel va changer ce numéro sera lié avec le courriel.

donc dans l'exemple ci-dessous, je récupère les UIDs sur la première étape, vérifiez si le dossier est vide aucun point de traitement du dossier sinon itérez pour tous les e-mails trouvés dans le dossier. Ensuite, récupérez chaque en-tête de courriel. Les en-têtes nous aideront à récupérer le sujet et à comparer le sujet du courriel avec celui que nous cherchons. Si le sujet correspond, continuez à copier et supprimez le courriel. Alors vous êtes fait. Simple que cela.

#!/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 = 'example.email@gmail.com'
    password = 'examplePassword'
    main_dictionary = main(username, password, 'INBOX', 'BOKNING', 'TMP_FOLDER')
    pprint.pprint(main_dictionary)
    exit(0)

informations utiles concernant imaplib Python-imaplib IMAP exemple avec Gmail et imaplib documentation.

0
répondu Thanos 2016-01-10 01:59:21