1. 程式人生 > >【Python入門】41.電子郵件之 POP3收取郵件

【Python入門】41.電子郵件之 POP3收取郵件

摘要:如何通過POP3,用Python收取電子郵件。

寫在前面:為了更好的學習python,博主記錄下自己的學習路程。本學習筆記基於廖雪峰的Python教程,如有侵權,請告知刪除。歡迎與博主一起學習Pythonヽ( ̄▽ ̄)ノ

摘要 本學習筆記基於廖雪峰的Python教程。歡迎與博主一起學習Pythonヽ( ̄▽ ̄)ノ 本節內容:如何通過POP3,用Python收取電子郵件。

目錄

電子郵件

POP3收取郵件

收取郵件通常用的是POP協議,目前版本號為3,俗稱POP3。

我們需要編寫一個MUA從MDA上收取郵件。

我們要用到Python中的兩個模組,poplib

email,分為兩大步驟:

1.用poplib下載郵件的原始文字 2.用email解析原始文字,還原郵件。

當然了,在這之前需要保證我們使用的郵箱已經開啟了POP3服務。

poplib下載郵件

首先引入poplib模組:

import poplib

準備登入POP3伺服器的相關資訊,包括郵箱地址、密碼和伺服器地址:

email = input('Email:')                # 輸入郵箱地址
password = input('Password:')          # 輸入密碼
pop3_server = input('POP3_server:'
) # 輸入POP3伺服器地址

連線POP3伺服器:

server = poplib.POP3(pop3_server)
server.set_debuglevel(1)                      # 開啟調式資訊
print(server.getwelcome().decode('utf-8'))    # 列印POP3伺服器歡迎資訊

需要注意的是,如果使用的郵箱pop服務有加密,則需要以加密的方法連線伺服器,像這樣:

server = poplib.POP3_SSL(pop3_server)

進行身份認證:

server.user(email)
server
.pass_(password)

返回郵箱的相關資訊:

print('Messages:%s. Size:%s' % server.stat())     # 返回郵件數目和佔用空間
resp, mails, octets = server.list()               # 獲取郵件列表
print(mails)                                      # 列印所有郵件編號及相應的大小

這裡stat()可以獲取郵件總數目及佔用空間。

list()可以獲取每一封郵件的編號即佔用空間。

獲取一封郵件:

index = len(mails)                                 # index為郵件總數目                            
resp, lines, octets = server.retr(index)           # 獲取最新一封郵件的資訊
msg_content = b'\r\n'.join(lines).decode('utf-8')  # 獲得整個郵件的原始文字

retr()可以返回郵件的全部文字,其中lines儲存的是文字的每一行內容。

接下來就是解析文字的部分,後面會介紹:

msg = Parser().parsestr(msg_content)             # 解析郵件原始文字

最後關閉連線:

server.quit()

解析郵件

解析郵件的過程與構造郵件正好相反。

首先,引入必要的模組:

from email.parser import Parser            # 解析模組
from email.header import decode_header     # 用於獲取標頭檔案的編碼資訊
from email.utils import pasrseaddr         # 用於格式化郵件資訊

import poplib

由於在解析郵件的過程中,會遇到編碼問題,需要進行相應的解碼才能正常顯示。

所以我們需要先定義相關函式用以解碼。

針對郵件的相關資訊,比如Subjict,name等,我們定義一個decode_str函式:

def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = valur.decode(charset)           # 如果文字中存在編碼資訊,則進行相應的解碼
    return value

針對郵件的文字內容,我們需要檢測編碼,否則,非UTF-8編碼的郵件都無法正常顯示,我們定義一個guess_charset函式:

def guess_charset(msg):
    charset = msg.get_charset()                             # 直接用get_charset()方法獲取編碼
    if charset is None:                                     # 如果獲取不到,則在原始文字中尋找
        content_type = msg.get('Content-Type', '').lower()  
        pos = content_type.find('charset=')                 # 找'charset='這個字串
        if pos >=0:                                         # 如果有,則獲取該字串後面的編碼資訊
            charset = content_type[pos+8:].strip()
    return charset

這裡lower()是把字串全改為小寫表示。

strip()是去除字串前後的空格字元。

準備好編碼的問題,就開始正式解析郵件吧。

把郵件內容解析為Message物件:

msg = Parser().parsestr(msg_content)

由於這個Message物件可能巢狀著其他MIMEBase物件,所以我們要遞迴地打印出Mseeage的層次結構:

def print_info(msg, indent=0):                              # indent用於縮排顯示 
    # 首先列印郵件的發件人,收件人和主題
    if indent == 0:
        for header in ['From', 'To', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header == 'Subject':                     # 解碼主題資訊
                    value = decode_str(value)
                else:                                       # 解碼發件人和收件人資訊
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = u'%s <%s>' % (name, addr)
            print('%s%s: %s' % ('  '* indent, header, value))   #'  ' *indent可以打印出2*indent個空格

    # 將組合郵件物件分離,         
    if (msg.is_multipart()): 
        parts = msg.get_payload()                           # 拿取msg的子物件
        for n, part in enumerate(parts):
            print('%spart %s' % ('  ' * indent, n))
            print('%s--------------------' % ('  ' * indent))
            print_info(part,indent + 1)

    # 逐一列印郵件物件
    else: 
        content_type = msg.get_content_type()               # 獲取郵件物件格式
        if content_type == 'text/plain' or content_type == 'text/html':  # 如果為文字郵件,則直接列印
            content = msg.get_payload(decode=True)
            charset = guess_charset(msg)                     # 檢測編碼
            if charset:
                content = content.decode(charset)           # 解碼
            print('%sText: %s' % ('  ' * indent, content))  # 列印內容
        else:
            print('%sAttachment: %s' % ('  ' * indent, content_type))  # 否則為附件,獲取附件資訊

整理一下上面的程式碼,就能用來收取郵件了,比如有這樣一封郵件: 這裡寫圖片描述

我們執行上面的程式碼,把顯示結果如下:

+OK QQMail POP3 Server v1.0 Service Ready(QQMail v2.0) 
Messages:19. Size:1335886 

From: 三貝 <[email protected]126.com> 
To: xxxxxxxx<[email protected]> 
Subject: POP3測試 
part 0 
-------------------- 
  part 0 
  -------------------- 
    Text: 你好,正在使用POP3收取郵件。 
  part 1 
  -------------------- 
    Text: <div style="line-height:1.7;color:#000000;..."><div>你好,正在使用...
 &nbsp; &nbsp;</div></div></span> 
part 1 
-------------------- 
  Attachment: image/png 

從列印的結構我們可以看出,這封郵件是一個MIMEMultipart,分為兩部分:

第一部分又是一個MIMEMultipart,這一部分包含一個純文字格式的MIMEText和HTML格式的MIMEText

第二部分是一個Image檔案。

小結

Python用POP3收取電子郵件分兩步:第一,使用poplib下載郵件原始文字;第二,使用email把原始文字解析為Message物件,然後將內容展示給使用者。

以上就是本節的全部內容,感謝你的閱讀。

下一節內容:資料庫

有任何問題與想法,歡迎評論與吐槽。

和博主一起學習Python吧( ̄▽ ̄)~*