Python學習:通過IMAP收郵件

IMAP
SMTP是用於發送電子郵件的協議,而IMAP規定如何與電子郵件服務提供商的服務器通信,取回發送到你的電子郵件地址的郵件
Python帶有一個imaplib模塊,還有第三方的imapclient、pyzmail模塊

import imapclient
#創建一個IMAPClient對象,大多數郵件提供商要求SSL加密,傳入ssl = True關鍵字參數
imapObj = imapclient.IMAPClient('imap.qq.com',ssl = True)

#取得IMAPClient後,調用login()方法,傳入用戶名和密碼字符串
imapObj.login('[email protected]','password')

搜索郵件:

1、選擇需要搜索的文件夾;2、必須調用IMAPClient對象的search()方法,傳入IMAP搜索關鍵詞字符串

選擇文件夾:幾乎每一個帳戶都默認有一個INBOX文件夾,但是也可以調用IMAPClient對象的list_folders()方法,獲取文件夾列表
list_folders()方法返回一個元組的列表,每一個元組包含一個文件夾信息
import pprint
pprint.pprit(imapObj.list_folders())

#要選擇一個文件夾進行搜索,就調用select_folder()方法,傳入該文件夾的名稱字符串

imapObj.select_folder('INBOX',readonly = True)


可以忽略select_folder()返回值,當搜索的文件夾不存在時。Python拋出imap.error異常
readonly = True關鍵字參數可以防止你在隨後的方法調用中,不小心更改或刪除該文件夾中的任何電子郵件

執行搜索:文件夾選中後就可以調用IMAPClient對象的search()方法搜索電子郵件
search()方法的參數是一個字符串列表,每一個格式化爲IMAP的搜索鍵

IMAP搜索鍵:

'ALL':返回該文件夾中的所有郵件。如果你請求一個大文件夾中的所有信息,可能會遇到imaplib的大小限制

'BEFORE/ON/SINCE date':分別返回給定的date之前、當天、之後IMAP服務器接受的消息,日期格式必須是05-Jul-2017
此外,雖然“SINCE 05-Jul-2017”將匹配7月5日當天和之後的消息,但是“BEFORE 05-Jul-2017”僅匹配7月5日之前的消息,不包括7月5日當天

'SUBJECT/BODY/TEXT string':分別返回string出現在主題、正文、主題或正文中的消息,如果string中有空格,就是用雙引號

'FROM/TO/CC/BCC string':返回所有信息,其中string分別出現在“from”郵件地址、“to”郵件地址、“cc”(抄送)地址、或“bcc”(密件抄送)地址
如果string中有多個郵件地址,就是用空格將他們分割開,並使用雙引號

'SEEN/UNSEEN':分別返回包含和不包含\Seen標記的所有信息。如果電子郵件已經被fetch()方法調用訪問,或者你曾在電子郵件程序中或網絡瀏覽器中點擊過它,
就會有\Seen標記,比較常用的說法是“已讀”而不是“已看”

'ANSWERED/UNANSERED':分別返回包含和不包含\Answered標記的所有信息,如果消息已答覆就會有\Answered標記

'DELERED/UNDELETED':分別返回包含和不包含\Deleted標記的所有信息,用delete_messages()方法刪除的郵件就會有\Deleted標記,直到調用expunge()方法才
會永久刪除

'DRAFT/UNDRAFT':分別返回包含和不包含\Draft標記的所有信息,草稿郵件通常保存在單獨的草稿文件夾中,而不是收件箱

'FLAGGED/UNFLAGGED':分別返回包含和不包含\Flagged標記的所有信息,這個標記通常用來標記電子郵件的“重要”或“緊急”

'LARGER/SMALLER N':分別返回大於或小於N個字節的所有信息

'NOT search-key':返回搜索鍵不會返回的那些信息

'OR search-key1 search-key2':返回符合第一個或者第二個搜索鍵的信息


imapObj.search(['all'])
imapObj.search(['ON 05-Jul-2017'])
imapObj.search(['SINCE 01-Jul-2017','BEFORE 05-Jul-2017'])
imapObj.search(['OR FROM [email protected] FROM [email protected]'])

#search不返回電子郵件本身,而是返回郵件的唯一整數ID(UID),然後可以將這些UID傳入fetch(),獲得郵件內容
UIDS = []
UIDS = imapObj.search(['all'])

大小限制:
如果搜索匹配大量的電子郵件,Python可能會拋出imap.error:got more than 10000 bytes的異常,必須斷開重連IMAP服務器
可以調整限制的字節數

import imaplib
imaplib._MAXLINE = 10000000

取郵件並標記爲已讀
獲取到UID的列表後,就可以調用IMAPClient對象的fetch()方法,獲得實際的電子郵件內容
UID列表是fetch()函數的第一個參數,第二個參數應該是['BODY[]'],它告訴fetch()下載UID列表中指定電子郵件的所有正文內容

rawMessages = imapObj.fetch(UIDS,['BODY[]'])
pprint.pprint(rawMessages)

打印結果:
返回值是消息的嵌套字典,其中以UID作爲鍵,每條消息同業也保存爲一個字典,包含兩個鍵'BODY[]'和'SEQ'
'BODY[]'映射到電子郵件的實際正文;'SEQ'鍵是序列號
形如:{UID:{'BODY[]':郵件正文內容,'SEQ':序列號}}

'BODY[]'鍵中的消息內容是相當難以理解的,這種格式被稱爲RFC822,專爲IMAP服務器讀取設計的,稍後通過pyzmail模塊解析

如果選擇一個文件夾來搜索,需要用關鍵字readonly = True參數來調用函數select_folder(),這樣做可以防止意外刪除電子郵件,
但是也意味着用fetch()方法獲取郵件內容,他們不會被標記爲已讀

如果確實需要在獲取的同時標記爲已讀,可以將readonly = False傳遞給select_folder()方法,即所選文件夾處於只讀模式


imapObj.select_folder('INBOX',readonly = False)

從原始信息中獲取電子郵件地址

通過pyzmail模塊解析這些原始信息,返回一個PyzMessage對象返回,是郵件的正文、主題、收件人、發件人以及其他字段信息


#導入pyzmail模塊後,調用pyzmail.PeekMessage.factory()函數,創建一個PyzMessage對象
import pyzmail
messageObj = pyzmail.PeekMessage.factory(rawMessages[40041]['BODY[]'])

get_subject()方法將主題返回爲一個簡單的字符串,get_addresses()針對傳入的字段(參數是'from','to','cc','bcc'),返回一個地址的元組列表
每一個元組包含兩個字符串,第一個是與該電子郵件地址關聯的名稱,第二個是電子郵件地址本身,如果請求的字段中沒有地址,返回一個空的列表
messageObj.get_subject()
messageObj.get_addresses('from')
messageObj.get_addresses('to')
messageObj.get_addresses('cc')
messageObj.get_addresses('bcc')


從原始消息中獲取正文

電子郵件可以是純文本、HTML或者兩者混合

純文本電子郵件只包含文本,而HTML電子郵件可以有顏色、字體、圖像、和其他功能

如果電子郵件是純文本,PyzMessage對象會將html_part屬性設爲None,同樣,當郵件只有HTML,PyzMessage對象會將text_part屬性設置爲None

否則,text_part或者html_part將有一個get_payload()方法,將電子郵件的正文返回爲bytes數據類型,但是這仍然不是我們可以使用的字符串,
最後一步對get_payload()返回的bytes值調用decode()方法。decode()方法接受一個參數:這條消息的字符編碼,保存在text_part.charset或
html_part.charset屬性中

if messageObj.text_part != None:
    messageConten = messageObj.text_part.get_payload().decode(text_part.charset)
    pprint.pprint(messageConten)
elif messageObj.html_part != None:
    messageConten = messageObj.html_part.get_payload().decode(html_part.charset)
    pprint.pprint(messageConten)
else:
    pass




刪除電子郵件

要刪除電子郵件,就需要想IMAPClient對象的delete_messages()方法傳入一個消息的UID列表,這爲電子郵件加上了\Deleted標記

調用expunge()方法,將永久刪除當前選中的文件夾中的帶\Deleted標誌的所有電子郵件
imapObj.select_folder('INBOX',readonly = False)
UIDs = imapObj.search('ON 09-Jul-2017')

imapObj.delete_messages(UIDs)
imapObj.expunge()

從IMAP服務器斷開
#調用IMAPClient對象的logout()方法

imapObj.logout()



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章