سؤال

أريد أن أكون قادرًا على نقل بريد إلكتروني في Gmail من صندوق الوارد إلى مجلد آخر باستخدام Python. أنا أستخدم Imaplib ولا يمكنني معرفة كيفية القيام بذلك.

هل كانت مفيدة؟

المحلول

لا يوجد أمر نقل صريح لـ 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)

نصائح أخرى

أما بالنسبة لـ Gmail ، بناءً على ذلك API العمل مع العلامات, ، الشيء الوحيد الذي يجب عليك فعله هو إضافة تسمية مصير وحذف تسمية 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)

أفترض أن المرء لديه 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()

لم يعمل أي من الحلول السابقة بالنسبة لي. لم أتمكن من حذف رسالة من المجلد المحدد ، ولم أتمكن من إزالة التسمية للمجلد عندما يكون التسمية المجلد المحدد. إليك ما انتهى به الأمر من أجل العمل بالنسبة لي:

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

أعلم أن هذا سؤال قديم للغاية ، ولكن بأي شكل من الأشكال. الحل المقترح بواسطة مانوج جوفيندان ربما يعمل بشكل مثالي (لم أختبره ولكن يبدو الأمر كذلك. المشكلة التي واجهتها واضطررت إلى حلها هي كيفية نسخ/نقل أكثر من بريد إلكتروني !!!

لذلك توصلت إلى حل ، ربما يكون لدى شخص آخر في المستقبل نفس المشكلة.

الخطوات بسيطة ، أقوم بالاتصال بحساب البريد الإلكتروني الخاص بي (Gmail) ، اختر المجلد لمعالجة (EG Box) جلب جميع UIDs ، بدلاً من رقم قائمة البريد الإلكتروني (البريد الإلكتروني). هذه نقطة حاسمة لإشعارها هنا. إذا جلبنا رقم قائمة رسائل البريد الإلكتروني ، ثم قمنا بمعالجة القائمة ، فسننتهي بمشكلة. عندما ننقل رسالة بريد إلكتروني ، تكون العملية بسيطة (انسخ في مجلد الوجهة وحذف البريد الإلكتروني من كل موقع حالي). تظهر المشكلة إذا كان لديك قائمة من رسائل البريد الإلكتروني على سبيل المثال 4 رسائل بريد إلكتروني داخل صندوق الوارد ونقوم بمعالجة البريد الإلكتروني الثاني في القائمة ثم الرقم 3 و 4 مختلفون ، فهي ليست رسائل البريد الإلكتروني التي اعتقدنا أنها ستكون ، والتي ستنتج في خطأ لأن عنصر القائمة رقم 4 لن يكون موجودًا لأن القائمة نقلت موقعًا واحدًا لأن وضعين كان فارغًا.

لذلك كان الحل الوحيد الممكن لهذه المشكلة هو استخدام UIDs. وهي أرقام فريدة لكل بريد إلكتروني. لذا ، بغض النظر عن كيفية تغيير البريد الإلكتروني ، سيتم إبطال هذا الرقم بالبريد الإلكتروني.

لذلك في المثال أدناه ، أحضر UIDs في الخطوة الأولى ، تحقق مما إذا كان المجلد فارغًا بدون نقطة لمعالجة المجلد الآخر الذي يكرر لجميع رسائل البريد الإلكتروني الموجودة في المجلد. قم بإحضار كل رأس بريد إلكتروني. ستساعدنا الرؤوس على جلب الموضوع ومقارنة موضوع البريد الإلكتروني مع البرنامج الذي نبحث عنه. إذا كان الموضوع يتطابق ، فاستمر في نسخ البريد الإلكتروني وحذفه. ثم انتهيت. سهل هكذا.

#!/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 IMAP مع Gmail و ال وثائق imaplib.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top