2010-08-20 2 views

ответ

33

Нет явной команды перемещения для 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) 
+2

Любые мысли о перемещении нескольких сообщений? вам нужно выполнить другой поиск и принять последнее сообщение с помощью email_ids [-1]? – ewalk

+3

Gmail IMAP * автоматически * делает '\ Deleted' /' EXPUNGE' для вас, когда вы 'COPY' сообщение' [Gmail]/Trash'. – dkarp

+0

@dkarp благодарит за информацию, которую вы предоставили. Я пробовал это с прошлой недели. –

4

Предположим, у вас есть uid электронного письма, которое будет перемещено.

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

Что касается Gmail, основываясь на его api working with labels, единственное, что вам нужно сделать, это добавление метки Dest и удаление метки 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

Это не сработало для меня. Он добавил метку desti_folder_name, но не удалил метку src_folder_name. Однако решение Маноя Говиндана работало для меня. – mernst

+0

Я могу подтвердить то же самое, но почему удаление не работает? Какое правильное решение? – sorin

+0

@sorin это работает для меня, возможно, вы делаете что-то неправильно. Я сделал это прямо сейчас после всех шагов за строкой ... – scraplesh

3

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

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

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

Итак, я пришел

Шаги просты, я подключаюсь к моей учетной записи электронной почты (GMAIL), чтобы выбрать папку для обработки (например, INBOX), чтобы получить все uids вместо электронной почты (например, s). Это ключевой момент, чтобы заметить здесь. Если мы выберем количество списков электронных писем, а затем обработаем список, у нас возникнет проблема. Когда мы перемещаем электронное письмо, процесс прост (копия в пункте назначения папку и удалить электронную почту из каждого текущего местоположения). Проблема возникает, если у вас есть список электронных писем, например. 4 письма внутри почтового ящика, и мы обрабатываем 2-й адрес электронной почты внутри списка, а номера 3 и 4 отличаются друг от друга, это не письма, которые, по нашему мнению, были бы такими, что приведет к ошибке, поскольку элемент списка 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 = '[email protected]' 
    password = 'examplePassword' 
    main_dictionary = main(username, password, 'INBOX', 'BOKNING', 'TMP_FOLDER') 
    pprint.pprint(main_dictionary) 
    exit(0) 

Полезная информация о imaplib Python — imaplib IMAP example with Gmail и imaplib documentation.

Смежные вопросы