溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python使用 poplib模塊實(shí)現(xiàn)收取郵件

發(fā)布時(shí)間:2020-09-23 17:08:54 來(lái)源:億速云 閱讀:186 作者:Leah 欄目:編程語(yǔ)言

本篇文章為大家展示了Python使用 poplib模塊實(shí)現(xiàn)收取郵件,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

使用 poplib 模塊收取郵件也很簡(jiǎn)單,該模塊提供了 poplib.POP3 和 poplib.POP3_SSL 兩個(gè)類,分別用于連接普通的 POP 服務(wù)器和基于 SSL 的 POP 服務(wù)器。

一旦使用 poplib.POP3 或 poplib.POP3_SSL 連接到服務(wù)器之后,接下來(lái)基本就按照 POP3 協(xié)議與服務(wù)器進(jìn)行交互。為了更好地理解 poplib 模塊的運(yùn)行機(jī)制,下面先簡(jiǎn)單介紹 POP3 協(xié)議內(nèi)容。

POP3 協(xié)議也屬于請(qǐng)求,響應(yīng)式交互協(xié)議,當(dāng)客戶端連接到服務(wù)器之后,客戶端向 POP 服務(wù)器發(fā)送請(qǐng)求,而 POP 服務(wù)器則對(duì)客戶端生成響應(yīng)數(shù)據(jù),客戶端可通過(guò)響應(yīng)數(shù)據(jù)下載得到郵件內(nèi)容。當(dāng)下載完成后,郵件客戶端可以刪除或修改任意郵件,而無(wú)須與電子郵件服務(wù)器進(jìn)行進(jìn)一步交互。

POP3 的命令和響應(yīng)數(shù)據(jù)都是基于 ASCII 文本的,并以 CR 和 LF(/r/n) 作為行結(jié)束符,響應(yīng)數(shù)據(jù)包括一個(gè)表示返回狀態(tài)的符號(hào)(+/)和描述信息。

請(qǐng)求和響應(yīng)的標(biāo)準(zhǔn)格式如下:

請(qǐng)求標(biāo)準(zhǔn)格式:命令 [參數(shù)] CRLF
響應(yīng)標(biāo)準(zhǔn)格式:+OK /[-ERR] description CRLF

POP3 協(xié)議客戶端的命令和服務(wù)器端對(duì)應(yīng)的響應(yīng)數(shù)據(jù)如下:

user name:向 POP 服務(wù)器發(fā)送登錄的用戶名。

pass string:向 POP 服務(wù)器發(fā)送登錄的密碼。

quit:退出 POP 服務(wù)器。

stat:統(tǒng)計(jì)郵件服務(wù)器狀態(tài),包括郵件數(shù)和總大小。

list [msg_no]:列出全部郵件或指定郵件。返回郵件編號(hào)和對(duì)應(yīng)大小。

retr msg_no:獲取指定郵件的內(nèi)容(根據(jù)郵件編號(hào)來(lái)獲取,編號(hào)從 1 開(kāi)始)。

dele msg_no:刪除指定郵件(根據(jù)郵件編號(hào)來(lái)刪除,編號(hào)從 1 開(kāi)始)。

noop:空操作。僅用于與服務(wù)器保持連接。

rset:用于撤銷 dele 命令。

poplib 模塊完全模擬了上面命令,poplib.POP3 或 poplib.POP3_SSL 為上面命令提供了相應(yīng)的方法,開(kāi)發(fā)者只要依次使用上面命令即可從服務(wù)器端下載對(duì)應(yīng)的郵件。

使用 poplib 收取郵件可分為兩步:

使用 poplib.POP3 或 poplib.POP3_SSL 按 POP3 協(xié)議從服務(wù)器端下載郵件。

使用 email.parser.Parser 或 email.parser.BytesParser 解析郵件內(nèi)容,得到 EmailMessage 對(duì)象,從 EmailMessage 對(duì)象中讀取郵件內(nèi)容。

下面程序示范了如何使用 poplib 模塊來(lái)收取郵件:

import poplib, os.path, mimetypes
from email.parser import BytesParser, Parser
from email.policy import default

# 輸入郵件地址, 口令和POP3服務(wù)器地址:
email = 'kongyeeku@qq.com'
password = '123456'
pop3_server = 'pop.qq.com'

# 連接到POP 3服務(wù)器:
#conn = poplib.POP3(pop3_server, 110)
conn = poplib.POP3_SSL(pop3_server, 995)
# 可以打開(kāi)或關(guān)閉調(diào)試信息:
conn.set_debuglevel(1)
# 可選:打印POP 3服務(wù)器的歡迎文字:
print(conn.getwelcome().decode('utf-8'))
# 輸入用戶名、密碼信息
# 相當(dāng)于發(fā)送POP 3的user命令
conn.user(email)
# 相當(dāng)于發(fā)送POP 3的pass命令
conn.pass_(password)
# 獲取郵件統(tǒng)計(jì)信息,相當(dāng)于發(fā)送POP 3的stat命令
message_num, total_size = conn.stat()
print('郵件數(shù): %s. 總大小: %s' % (message_num, total_size))
# 獲取服務(wù)器上的郵件列表,相當(dāng)于發(fā)送POP 3的list命令
# resp保存服務(wù)器的響應(yīng)碼
# mails列表保存每封郵件的編號(hào)、大小
resp, mails, octets = conn.list()
print(resp, mails)
# 獲取指定郵件的內(nèi)容(此處傳入總長(zhǎng)度,也就是獲取最后一封郵件)
# 相當(dāng)于發(fā)送POP 3的retr命令
# resp保存服務(wù)器的響應(yīng)碼
# data保存該郵件的內(nèi)容
resp, data, octets  = conn.retr(len(mails))
# 將data的所有數(shù)據(jù)(原本是一個(gè)字節(jié)列表)拼接在一起
msg_data = b'\r\n'.join(data)
# 將字符串內(nèi)容解析成郵件,此處一定要指定policy=default
msg = BytesParser(policy=default).parsebytes(msg_data)       #①
print(type(msg))
print('發(fā)件人:' + msg['from'])
print('收件人:' + msg['to'])
print('主題:' + msg['subject'])
print('第一個(gè)收件人名字:' + msg['to'].addresses[0].username)
print('第一個(gè)發(fā)件人名字:' + msg['from'].addresses[0].username)
for part in msg.walk():
    counter = 1
    # 如果maintype是multipart,說(shuō)明是容器(用于包含正文、附件等)
    if part.get_content_maintype() == 'multipart' :
        continue
    # 如果maintype是multipart,說(shuō)明是郵件正文部分
    elif part.get_content_maintype() == 'text':
        print(part.get_content())
    # 處理附件
    else :
        # 獲取附件的文件名
        filename = part.get_filename()
        # 如果沒(méi)有文件名,程序要負(fù)責(zé)為附件生成文件名
        if not filename:
            # 根據(jù)附件的contnet_type來(lái)推測(cè)它的后綴名
            ext = mimetypes.guess_extension(part.get_content_type())
            # 如果推測(cè)不出后綴名
            if not ext:
                # 使用.bin作為后綴名
                ext = '.bin'
            # 程序?yàn)楦郊?lái)生成文件名
            filename = 'part-%03d%s' % (counter, ext)
        counter += 1
        # 將附件寫(xiě)入的本地文件
        with open(os.path.join('.', filename), 'wb') as fp:
            fp.write(part.get_payload(decode=True))
# 退出服務(wù)器,相當(dāng)于發(fā)送POP 3的quit命令
conn.quit()

上面程序通過(guò) poplib 模塊使用 POP3 命令從服務(wù)器端下載郵件,其實(shí)就是依次發(fā)送 user、pass、stat、list、retr 命令的過(guò)程。當(dāng) retr 命令執(zhí)行完成后,將得到最后一封郵件的數(shù)據(jù) data,該 data 是一個(gè) list 列表,因此程序需要先將這些數(shù)據(jù)拼接成一個(gè)整體,然后使用 ① 號(hào)代碼將郵件數(shù)據(jù)恢復(fù)成 EmailMessage 對(duì)象。

這里有一點(diǎn)需要指出,程序在創(chuàng)建 BytesParser(解析字節(jié)串格式的郵件數(shù)據(jù))或 Parser(解析字符串格式的郵件數(shù)據(jù))時(shí),必須指定 policy=default;否則,BytesParse 或 Parser 解析郵件數(shù)據(jù)得到的就是過(guò)時(shí)的 Message 對(duì)象,處理起來(lái)非常不方便。程序在 ① 號(hào)代碼之后特意輸出了解析得到的 msg 類型,此時(shí)應(yīng)該看到的是 EmailMesssage,而不是過(guò)時(shí)的 Message 對(duì)象。

在 ① 號(hào)代碼之前,就是完成 poplib 模塊收取郵件的第一步,即從服務(wù)器端下載郵件;在 ① 號(hào)代碼之后,就是完成 poplib 模塊收取郵件的第二步,也就是解析郵件內(nèi)容。

如果程序要獲取郵件的發(fā)件人、收件人和主題,直接通過(guò) EmailMessage 的相應(yīng)屬性來(lái)獲取即可,與前面為 EmailMessage 設(shè)置發(fā)件人、收件人和主題的方式是對(duì)應(yīng)的。

如果程序要讀取 EmailMessage 的各部分,則需要調(diào)用該對(duì)象的 walk() 方法,該方法返回一個(gè)可迭代對(duì)象,程序使用 for 循環(huán)遍歷 walk() 方法的返回值,對(duì)郵件內(nèi)容進(jìn)行逐項(xiàng)處理:如果郵件某項(xiàng)的 maintype 是 'multipart',則說(shuō)明這一項(xiàng)是容器,用于包含郵件內(nèi)容、附件等其他項(xiàng)。如果郵件某項(xiàng)的 maintype 是 'text',則說(shuō)明這一項(xiàng)的內(nèi)容是文本,通常就是郵件正文或文本附件。對(duì)于這種文本內(nèi)容,程序直接將其輸出到控制臺(tái)中。如果郵件某項(xiàng)的 maintype 是其他,則說(shuō)明這一項(xiàng)的內(nèi)容是附件,程序?qū)⒏郊?nèi)容保存在本地文件中。
運(yùn)行上面程序,可以看到程序收取了指定郵件的最后一封郵件,并將郵件內(nèi)容輸出到控制臺(tái)中,將郵件附件保存在本地文件中。

上述內(nèi)容就是Python使用 poplib模塊實(shí)現(xiàn)收取郵件,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI