Python 用POP接收郵件


一、簡介
  POP(Post Office Protocal)最長用的POP版本是POP3,因此本文是以POP3為主。POP3非常簡單,可以用來從郵件服務器上下載郵件,然后刪除這些郵件。功能非常有限,后面講解的IMAP完勝它,不過作為入門級的,還是有必要介紹一下,也對學習SMTP有幫助。
  Python提供了poplib模塊,它提供了使用POP的便利接口。
二、實例
  由於pop3功能較IMAP非常有限,而且我最后的程序並沒有使用pop3,所以,不詳細講解,下面通過一個例子來說明下較為常見的功能。
  這個例子的功能為進入郵箱,查看所有的郵件。首先顯示郵件的發件人、主題,查看郵箱主題內容。
1. 需要模塊

import email, poplib, sys

2. 連接POP3服務器,登錄個人郵箱賬戶
  poplib提供POP3()方法和POP3_SSL()方法連接POP3服務器,區別和SMTP一樣。gmail仍然使用POP3_SSL()方式,並返回class POP3實例

p = poplib.POP3_SSL('pop.gmail.com') 

  使用POP3.user(), POP3.pass_()方法來登錄個人賬戶

try:
    p.user(user) 
    p.pass_(passwd)
except poplib.error_proto: #可能出現的異常
    print('login failed')

3. 現在已經進入個人賬戶,下一步,利用POP3.list()函數查看郵箱內郵件信息。

  關於list()函數的詳細說明,請點擊這里
list()函數有三個返回值,分別是:response, listings, octets

  • response 應答信息,我測試中出現的結果:

    

  以b開頭的字符串是Byte類型,我在實際測試的時候,返回的信息幾乎都是Byte類型的。關於此類型及和普通字符串的轉化會在后面舉例說明。

  • listings 是形如['message_id message_size',...]若干各message-id和message_size構成的list。后面就是通過message_id來檢索郵件。我測試中出現的結果:

  

  • octets 不是特別清楚啥意思。
response, listings, octets = p.list()

4. 最重要的就是listings數據

  如上面解釋的,listings是個list類型的數據,接下來我們取出listings中的message_id,也就是上面的 "1" "2" "3" "4" ...

for listing in listings: #每次需要一個listing
number, size = listing.split() #由於number和size是以空格分隔,所以利用split()函數分開,split()默認以' '為分隔

  現在我們就取出了我們需要的message_id,也就是number,注意number需要從Byte類型轉化為字符串類型。

5. POP3.top()函數

  利用此函數,取出郵件的headers,如下:

response, lines, octets = p.top(number , 0)

  lines存儲內容,下面先轉化成Message類型(lines默認為標准字符串類型,僅供說明,以實際代碼為准)

message = email.message_from_string('\n'.join(lines))

6. 已經生成Message類,可以利用頭部信息來查看From, Subject等信息

for header in 'From', 'To', 'Subject', 'Date':
    if header in message:
        print(header + ':' , message[header]) 

  注意,此時的message[header]可能不會輸出我們想看到的內容,有可能出現格式錯亂問題,比如中英文的轉化,所以還需要特殊來處理。處理方式請繼續往下看IMAP部分。

7. 取出郵件所有信息
  上面的top()函數只取出header信息以及根據參數確定的n行內容,如果用戶希望查看郵件所有內容,那利用POP3.retr()函數取出

response, lines, octets = p.retr(number)

  還是將lines中的內容轉換成Message類型:

message = email.message_from_string('\n'.join(lines))

8. 已經有了郵件所有信息,可以通過Message.get_payload()取出郵件正文了。

  但是,get_payload()函數並不一定返回郵件正文。以下是官方說明:
Return the current payload, which will be a list of Message objects when is_multipart() is True, or a string when is_multipart() is False. 
  在實際測試中,返回的就是a list of Message objects,這個問題困擾我很長時間,最終還是解決了,通過以下方法:

maintype = message.get_content_maintype()
if maintype == 'multipart':
    for part in message.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()        

9. 此時,mail_content就是郵件正文了.

  當然,如果是中文的話,這件事仍未完,還需要將它轉化未'gbk',利用如下方式:

mail_content = mail_content.decode('gbk')

10. 到現在,基本已經大功告成了,能夠取出郵箱中所有的郵件,並查看郵件的header內容和郵件正文了^_^
三、完整代碼:

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

import email, getpass, poplib, sys

hostname = 'pop.gmail.com'
user = 'myUserName@gmail.com'
passwd = '***'

p = poplib.POP3_SSL('pop.gmail.com') #與SMTP一樣,登錄gmail需要使用POP3_SSL() 方法,返回class POP3實例
try:
    # 使用POP3.user(), POP3.pass_()方法來登錄個人賬戶
    p.user(user) 
    p.pass_(passwd)
except poplib.error_proto: #可能出現的異常
    print('login failed')
else:
    response, listings, octets = p.list()
    for listing in listings:
        number, size = listing.split() #取出message-id
        number = bytes.decode(number) 
        size = bytes.decode(size) 
        print('Message', number, '( size is ', size, 'bytes)')
            print()
        response, lines, octets = p.top(number , 0)
        # 繼續把Byte類型轉化成普通字符串
        for i in range(0, len(lines)):
            lines[i] = bytes.decode(lines[i])
        #利用email庫函數轉化成Message類型郵件
        message = email.message_from_string('\n'.join(lines))
        # 輸出From, To, Subject, Date頭部及其信息
        for header in 'From', 'To', 'Subject', 'Date':
            if header in message:
            print(header + ':' , message[header]) 
        #與用戶交互是否想查看郵件內容
        print('Read this message [ny]')
        answer = input()
        if answer.lower().startswith('y'):
            response, lines, octets = p.retr(number) #檢索message並返回
            for i in range(0, len(lines)):
                lines[i] = bytes.decode(lines[i])
            message = email.message_from_string('\n'.join(lines)) 
            print('-' * 72)
            maintype = message.get_content_maintype()
            if maintype == 'multipart':
                for part in message.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()
            try:
                mail_content = mail_content.decode('gbk')
            except UnicodeDecodeError:
                print('Decoding to gbk error')
                sys.exit(1)
            print(mail_content)
        print()
        print('Delete this message? [ny]')
        answer = input()
        if answer.lower().startswith('y'):
            p.dele(number)
            print('Deleted')
finally:
    print('log out')
    p.quit()
        

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM