web-dev-qa-db-ja.com

Pythonとimaplibを使用してGMailでメールを移動する

Pythonを使用して、GMailのメールを受信トレイから別のフォルダに移動できるようにしたい。私はimaplibを使用していますが、その方法がわかりません。

27
Dan

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)
37
Manoj Govindan

Gmailについては、その ラベルを使用するAPI に基づいて、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)
5
scraplesh

移動されるメールの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
Avadhesh

以前の解決策はどれも私にとってうまくいきませんでした。選択したフォルダーからメッセージを削除できず、ラベルが選択したフォルダーの場合、フォルダーのラベルを削除できませんでした。これが私のために働いた結果です:

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
3
Neal Young

これは非常に古い質問であることは知っていますが、とにかく。 Manoj Govindan によって提案された解決策はおそらく完全に機能します(私はテストしていませんが、そのように見えます。私が遭遇し、解決しなければならなかった問題は、複数のメールをコピー/移動する方法です!! !

だから私は解決策を思いつきました、多分将来の誰かが同じ問題を抱えているかもしれません。

手順は簡単です。メール(GMAIL)アカウントに接続して、処理するフォルダー(INBOXなど)を選択し、メールのリスト番号ではなく、すべてのuidを取得します。これは、ここで注意すべき重要なポイントです。メールのリスト数を取得してからリストを処理すると、問題が発生します。電子メールを移動するときのプロセスは簡単です(宛先フォルダーにコピーして、現在の各場所から電子メールを削除します)。メールのリストがある場合、問題が発生します。受信トレイ内で4通のメールがあり、リスト内で2通目のメールを処理する場合、番号3と4は異なります。それらは、そうであると思ったメールではなく、リストアイテム番号4はエラーになるため、エラーになります2ポジションが空だったためにリストが1ポジション下に移動したため、存在します。

したがって、この問題の唯一の可能な解決策は、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 — Gmailでのimaplib IMAPの例 および imaplibのドキュメント

1
Thanos