天天看點

python 接收郵件伺服器位址_Python 用IMAP接收郵件

一、簡介

IMAP(Internet Message Access Protocol),這個協定與POP一樣,也是從郵件伺服器上下載下傳郵件到本機,不過IMAP比POP的功能要更加強大些,IMAP除支援POP所有功能外,還支援以下功能:

多個郵件檔案夾(收件箱、發件箱、垃圾郵件...)

IMAP伺服器上進行标記如:Seen, Replied, Read, Deleted

在伺服器端的檔案夾之間拷貝和移動郵件

...

在IMAP的各版本中,最流行的是IMAP4。我們就使用IMAP4

由于,我需要搜尋是否有未讀郵件,也就是利用郵件伺服器的Flag,是以IMAP是非常适合的,我的程式就利用的是IMAP。

在Python的标準庫包含一個imaplib子產品,可以利用這個子產品。但是,這個子產品的缺陷就是把大量解析的工作留給用戶端程式員。

二、IMAPClient

IMAPClient是一個非常受歡迎的IMAPCLient包,這個子產品不在标準Python庫中。IMAPClient包是由一名叫做Menno Smits的Python程式員編寫的。官網網址:http://imapclient.freshfoo.com/。可以在這裡檢視手冊文檔。這個包是基于标準庫imaplib,不過要更強大。下面我們來介紹下怎樣安裝。

1. virtualenv

說實話,我本人對virtualenv的了解也不透徹,以字面上來了解為虛拟環境。可以把一些子產品、包安裝在特定的virtualenv裡,一旦安裝了virtualenv,你就建立任意多個自組織的虛拟python環境,在這個環境裡,可以安裝、下載下傳包。

好吧,廢話就不多說,直接說方法。

這裡是virtualenv的詳細說明,上面介紹了非常詳細的安裝方法,按照我自己的經驗,可以簡化為以下步驟:

$ [sudo] pip install virtualenv

$ [sudo] pip install https://github.com/pypa/virtualenv/tarball/develop

$ curl -O https://pypi.python.org/packages/source/v/virtualenv/ virtualenv-X.X.tar.gz

$ tar xvfz virtualenv-X.X.tar.gz

$ cd virtualenv-X.X

$ [sudo] python setup.py install

注意,上面下載下傳的 virtualenv-X.X.tar.gz 中的X是型号,需要把它改成數字,詳細版本類型可以參考:https://pypi.python.org/packages/source/v/virtualenv/

這樣,virtualenv已經安裝好。下面需要建立虛拟環境執行個體,步驟如下:

$ virtualenv --no-site-packages myenv

$ cd myenv

2. 安裝IMAPClient

myenv 為自己定義的虛拟環境的名字。這樣,我們已經在myenv裡面,接下來就可一安裝IMAPClient包了。步驟如下:

$ sudo pip install imapclient

$ python -c 'import imapclient'

此時,可以在python下使用imapclient子產品,但是不能在python3下使用,在網上查了一些資料,尤其是看了上面的那個介紹virtualenv的網頁,沒找到有用的,但是,回頭發現,這個imapclient是好使的了,不用進入gmapenv,直接使用即可,got it!

注意,上面用到了pip工具,如果沒有的話一定要安裝啊。

$ sudo apt-get install pip

三、開始正式學習IMAP1. 因為可能會出現中文,是以在程式的最上面,必須加上如下代碼:

#-*- encoding: utf-8 -*-#-*- encoding: gbk -*-

2. 所需子產品

importgetpass, email, sysfrom imapclient import IMAPClient

3. 連接配接服務、登入賬戶

這一步也沒什麼好講的。代碼如下:

#通過以下方式連接配接smtp伺服器,沒有考慮異常情況,詳細請參考官方文檔

c = IMAPClient(hostname = 'imap.gmail.com', ssl=True)try:

c.login(username, passwd)#登入個人帳号

exceptc.Error:print('Could not log in')

sys.exit(1)

4. 進入收件箱,檢視未讀郵件

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

result= c.search('UNSEEN')

利用select_folder()函數進行檔案夾,'INBOX'為收件箱,readonly = True 表明隻讀并不修改任何資訊

利用search()函數選擇想要的郵件,'UNSEEN'是郵件的flag,關于郵件的flag就不特别說明了,傳回郵件的message-id

5. 有了未讀郵件的ID(result),下面利用fetch()函數将郵件取來(下載下傳到本機)

msgdict = c.fetch(result, ['BODY.PEEK[]'] )

通過fetch()函數取得郵件内容,fetch()的詳細介紹請見這裡

fetch(self, message, data) 其中self參數可忽略,message為message_id, data 的作用是抓取message中的哪些部分。  官方文檔中沒有給出data的其他可選的參數,我一開始怎麼都不找到,最終在stackoverflow中進行提問,一位大哥把這個文檔介紹給我,在 6.4.5 FETCH Command 。這裡面非常詳細的介紹了各個函數的各種細節,當然也可以查到data其他可選的參數 6.4.5 表示的是原書的節。特别感謝這位哥們,人類的力量是無窮的啊!

我們隻需要'BODY.PEEK[]'即可。

6. 已經把郵件取出,下面開始解析郵件

for message_id, message inmsgdict.items():

e= email.message_from_string(message['BODY[]']) #生成Message類型

7. 得到的 e 即為Message類型的郵件,先面開始将又将中解析出'From', 'Subject'

還記得上面在POP講解中,我們遇到的不能顯示中文的問題嗎?在IMAP中仍會出現,下面就講解解決辦法

由于'From', 'Subject' header有可能有中文,必須把它轉化為中文,在這個點上,耽誤了我很長時間,最終在網上查到了一個方法:http://blog.csdn.net/bonnshore/article/details/8729984 雖然不是很明白,但是能把問題解決就是王道。代碼如下:

subject = email.header.make_header(email.header.decode_header(e['SUBJECT'])) #必須保證包含subject

mail_from = email.header.make_header(email.header.decode_header(e['From']))

8. 從Message e中解析出content正文

同上一篇的POP一樣,根據get_payload()傳回的不同類型,選擇解析方法,代碼如下:

maintype =e.get_content_maintype()if maintype == 'multipart':for part ine.get_payload():if part.get_content_maintype() == 'text':

mail_content= part.get_payload(decode=True).strip()elif maintype == 'text':

mail_content= e.get_payload(decode=True).strip()#此時,需要把content轉化成中文,利用如下方法:

try:

mail_content= mail_content.decode('gbk')exceptUnicodeDecodeError:print('decode error')

sys.exit(1)

9. 至此,我們已經完成了檢視是否有未讀郵件。如果有的話将未讀郵件的'From', 'Subject', content解析出來。正如上面完成的 mail_from, subject, mail_content一樣,現在可以完美的顯示,即使有中文!

四、完整代碼

#-*- encoding: utf-8 -*-#-*- encoding: gbk -*-

#因為可能會用到中文,是以必須有上面的這兩句話

#引入子產品及IMAPClient類

importgetpass, email, sysfrom imapclient importIMAPClient

hostname= 'imap.gmail.com' #gmail的smtp伺服器網址

username = '[email protected]'passwd= '***'c= IMAPClient(hostname, ssl= True) #通過一下方式連接配接smtp伺服器,沒有考慮異常情況,詳細請參考官方文檔

try:

c.login(username, passwd)#登入個人帳号

exceptc.Error:print('Could not log in')

sys.exit(1)else:

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

#利用select_folder()函數進行檔案夾,'INBOX'為收件箱,readonly = True 表明隻讀并不修改任何資訊

result = c.search('UNSEEN')

msgdict = c.fetch(result, ['BODY.PEEK[]'] )

#現在已經把郵件取出來了,下面開始解析郵件

for message_id, message inmsgdict.items():

e= email.message_from_string(message['BODY[]']) #生成Message類型#由于'From', 'Subject' header有可能有中文,必須把它轉化為中文

subject = email.header.make_header(email.header.decode_header(e['SUBJECT']))

mail_from= email.header.make_header(email.header.decode_header(e['From']))#解析郵件正文

maintype =e.get_content_maintype()if maintype == 'multipart':for part ine.get_payload():if part.get_content_maintype() == 'text':

mail_content= part.get_payload(decode=True).strip()elif maintype == 'text':

mail_content= e.get_payload(decode=True).strip()#此時,需要把content轉化成中文,利用如下方法:

try:

mail_content= mail_content.decode('gbk')exceptUnicodeDecodeError:print('decode error')

sys.exit(1)else:print('new message')print('From:', mail_from)print('Subject:', subject)

getstr= input('if you wanna read it, input y:')if getstr.startswith('y'):print('-'*10, 'mail content', '-'*10)print(mail_content.replace('

', '\n'))print('-'*10, 'mail content', '-'*10)

finally:

c.logout()

五、總結

至此,我們已經學習了利用Python編寫郵件服務的所有非常基本的内容,由于我的需求不是很高,目标不是做成一個功能強大的郵箱用戶端,是以諸如:MIME、附件、圖檔等功能都沒有學習,當然也沒有介紹。

因為我們現在接收的郵件,大多數都是MIME格式的,不過上文的包含了點解析MIME格式郵件的代碼。詳細請參考《Foundations of Python3 Network Programming. 2nd Edition》Chaper E-mail Composition and Decoding。