Tôi muốn có thể di chuyển email trong Gmail từ hộp thư đến đến thư mục khác bằng Python. Tôi đang sử dụng imaplib và không thể tìm ra cách để làm điều đó.Di chuyển email trong Gmail bằng Python và imaplib
Trả lời
Không có lệnh di chuyển rõ ràng cho IMAP. Bạn sẽ phải thực hiện một số COPY
theo sau là STORE
(có cờ phù hợp để biểu thị việc xóa) và cuối cùng là expunge
. Ví dụ được đưa ra dưới đây hoạt động để di chuyển thư từ một nhãn sang nhãn khác. Có thể bạn sẽ muốn thêm nhiều kiểm tra lỗi hơn.
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)
Bất kỳ suy nghĩ nào về việc di chuyển nhiều thư? bạn có phải thực hiện tìm kiếm khác và nhận thư mới nhất với email_ids [-1] không? – ewalk
Gmail IMAP * tự động * thực hiện '\ Deleted' /' EXPUNGE' cho bạn khi bạn 'COPY' gửi thư thành' [Gmail]/Thùng rác'. – dkarp
@dkarp cảm ơn thông tin bạn đã cung cấp. Tôi đã cố gắng này từ 1 tuần qua. –
Tôi cho rằng có một địa chỉ email sẽ được di chuyển.
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()
Đối với Gmail, dựa trên api working with labels của nó, điều duy nhất để bạn có thể làm là thêm nhãn đích và xóa nhãn 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)
Điều này không hiệu quả đối với tôi. Nó đã thêm nhãn desti_folder_name, nhưng nó không loại bỏ nhãn src_folder_name. Tuy nhiên, giải pháp của Manoj Govindan đã làm việc cho tôi. – mernst
Tôi có thể xác nhận tương tự, nhưng tại sao việc xóa không hoạt động? Giải pháp chính xác là gì? – sorin
@sorin này hoạt động cho tôi, bạn có thể đang làm điều gì sai. Tôi đã làm nó ngay bây giờ sau tất cả các bước theo dòng ... – scraplesh
Không ai trong số các giải pháp trước đó từng làm việc cho tôi. Tôi không thể xóa thư từ thư mục đã chọn và không thể xóa nhãn cho thư mục khi nhãn là thư mục đã chọn. Dưới đây là những gì đã kết thúc với tôi:
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
Tôi biết rằng đây là một câu hỏi rất cũ, nhưng bất kỳ cách nào. Giải pháp được đề xuất bởi Manoj Govindan có thể hoạt động hoàn hảo (tôi chưa thử nghiệm nhưng có vẻ như nó. Vấn đề mà tôi gặp phải và tôi phải giải quyết là cách sao chép/di chuyển nhiều hơn một email !!!
Vì vậy, tôi đã đến
Các bước đơn giản, tôi kết nối với tài khoản email của tôi (GMAIL) chọn thư mục để xử lý (ví dụ INBOX) tìm nạp tất cả các uids, thay vì email (Đây là một điểm quan trọng cần lưu ý ở đây Nếu chúng tôi lấy số danh sách email và sau đó chúng tôi đã xử lý danh sách chúng tôi sẽ gặp phải sự cố. Khi chúng tôi chuyển email, quá trình này rất đơn giản (sao chép tại đích và xóa email từ từng vị trí hiện tại). Sự cố xuất hiện nếu bạn có danh sách email, ví dụ: 4 email bên trong hộp thư đến và chúng tôi xử lý email thứ 2 trong danh sách sau đó số 3 và 4 khác nhau, chúng không phải là email mà chúng tôi cho là chúng sẽ bị lỗi vì mục danh sách số 4 sẽ không tồn tại vì danh sách đã di chuyển một vị trí xuống vì 2 vị trí trống.
Vì vậy, giải pháp duy nhất có thể cho vấn đề này là sử dụng UID. Đó là số duy nhất cho mỗi email. Vì vậy, không có vấn đề làm thế nào email sẽ thay đổi số này sẽ được ràng buộc với email. Vì vậy, trong ví dụ bên dưới, tôi tìm nạp UID ở bước đầu tiên, kiểm tra xem thư mục có trống không có điểm xử lý thư mục khác lặp lại cho tất cả các email được tìm thấy trong thư mục hay không. Tiếp theo tìm nạp từng Tiêu đề email. Tiêu đề sẽ giúp chúng tôi tìm nạp Chủ đề và so sánh chủ đề của email với chủ đề mà chúng tôi đang tìm kiếm. Nếu chủ đề phù hợp, sau đó tiếp tục sao chép và xóa email. Sau đó bạn đã xong. Đơn giản như thế.
#!/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)
Thông tin hữu ích về imaplib Python — imaplib IMAP example with Gmail và imaplib documentation.
GMail không có thư mục: P – leoluk