Переместите электронное письмо в GMail с помощью Python и imaplib - PullRequest
24 голосов
/ 20 августа 2010

Я хочу иметь возможность перемещать электронную почту в GMail из папки «Входящие» в другую папку, используя Python.Я использую imaplib и не могу понять, как это сделать.

Ответы [ 5 ]

37 голосов
/ 20 августа 2010

Для IMAP нет явной команды перемещения. Вам нужно будет выполнить COPY, затем STORE (с подходящим флагом, указывающим на удаление) и, наконец, expunge. Приведенный ниже пример работал для перемещения сообщений от одной метки к другой. Возможно, вы захотите добавить больше проверки ошибок.

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)
5 голосов
/ 16 сентября 2011

Что касается Gmail, на основе его API, работающего с метками , единственное, что вам нужно сделать, это добавить dest label и удалить метку 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)
4 голосов
/ 03 сентября 2010

Полагаю, у кого-то есть электронный адрес, который будет перемещен.

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()
3 голосов
/ 07 января 2013

Ни одно из предыдущих решений не сработало для меня.Я не смог удалить сообщение из выбранной папки и не смог удалить ярлык для папки, когда ярлык был выбранной папкой.Вот что у меня получилось:

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
1 голос
/ 10 января 2016

Я знаю, что это очень старый вопрос, но никак.Предлагаемое решение Manoj Govindan , вероятно, работает отлично (я не проверял его, но похоже, что это. Проблема, с которой я сталкиваюсь и которую мне пришлось решить, состоит в том, как копировать / перемещать более одного электронного письма !!!

Итак, я нашел решение, возможно, у кого-то еще в будущем может возникнуть такая же проблема.

Шаги просты, я подключаюсь к своей учетной записи электронной почты (GMAIL), выбираю папку для обработки (например, INBOX) получить все идентификаторы вместо номера списка адресов электронной почты. Это очень важно отметить здесь. Если мы получим список адресов электронной почты, а затем обработаем список, у нас возникнет проблема. Когда мы переместимсяэлектронная почта процесс прост (скопируйте в папку назначения и удалите электронную почту из каждого текущего местоположения). Проблема возникает, если у вас есть список электронных писем, например, 4 электронных письма внутри почтового ящика, и мы обрабатываем второе электронное письмо внутри списка, затем номер 3и 4 разные, это не те электронные письма, которые мы думали, что они будут, что приведет к ошибке, потому что lisДля пункта № 4 он не будет существовать, поскольку список переместился на одну позицию вниз, поскольку позиция 2 была пустой.

Таким образом, единственным возможным решением этой проблемы было использование идентификаторов UID.Какие уникальные номера для каждого письма.Поэтому независимо от того, как электронная почта изменится, этот номер будет связан с электронной почтой.

Так что в приведенном ниже примере я получаю UID на первом шаге, проверяю, является ли папка пустой, нет смысла обрабатывать папку, иначеитерация для всех электронных писем, найденных в папке.Затем загрузите каждый заголовок электронной почты.Заголовки помогут нам выбрать тему и сравнить тему письма с тем, который мы ищем.Если тема совпадает, продолжайте копировать и удалять электронную почту.Тогда вы сделали.Все просто.

#!/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)

Полезная информация, касающаяся imaplib Python - пример IMAPlib imaplib с Gmail и документация imaplib .

...