与Python和Imaplib一起在Gmail中移动电子邮件
题
我希望能够使用Python将Gmail中的电子邮件从收件箱中移动到另一个文件夹。我正在使用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, ,您唯一要做的就是添加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)
我想一个将要移动的电子邮件的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
我知道这是一个非常古老的问题,但是无论如何。提出的解决方案 Manoj Govindan 可能工作得很完美(我没有测试过,但看起来像它。我遇到和解决的问题是如何复制/移动多个电子邮件!!!
因此,我提出了解决方案,也许将来其他人可能会有同样的问题。
这些步骤很简单,我连接到我的电子邮件(gmail)帐户选择要处理的文件夹(例如收件箱)获取所有UID,而不是电子邮件列表号。这是这里要注意的关键点。如果我们获取了电子邮件列表的列表,然后我们处理了列表,我们最终会遇到问题。当我们移动电子邮件时,该过程很简单(在目标文件夹中复制并从每个当前位置删除电子邮件)。如果您有一封电子邮件列表,例如收件箱中的4封电子邮件,并且我们处理列表中的第二封电子邮件,那么第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 = '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文档.