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

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


*寫在前面:為了更好的學(xué)習(xí)python沟堡,博主記錄下自己的學(xué)習(xí)路程。本學(xué)習(xí)筆記基于廖雪峰的Python教程矢空,如有侵權(quán)航罗,請(qǐng)告知?jiǎng)h除。歡迎與博主一起學(xué)習(xí)Pythonヽ( ̄▽ ̄)? *


摘要
本學(xué)習(xí)筆記基于廖雪峰的Python教程屁药。歡迎與博主一起學(xué)習(xí)Pythonヽ( ̄▽ ̄)?
本節(jié)內(nèi)容:如何通過(guò)POP3粥血,用Python收取電子郵件。

目錄

電子郵件
POP3收取郵件
poplib下載郵件
解析郵件
小結(jié)

電子郵件

POP3收取郵件

收取郵件通常用的是POP協(xié)議者祖,目前版本號(hào)為3立莉,俗稱POP3。

我們需要編寫一個(gè)MUA從MDA上收取郵件七问。

我們要用到Python中的兩個(gè)模塊蜓耻,poplibemail,分為兩大步驟:

1.用poplib下載郵件的原始文本
2.用email解析原始文本械巡,還原郵件刹淌。

當(dāng)然了饶氏,在這之前需要保證我們使用的郵箱已經(jīng)開啟了POP3服務(wù)。

poplib下載郵件

首先引入poplib模塊:

import poplib

準(zhǔn)備登錄POP3服務(wù)器的相關(guān)信息有勾,包括郵箱地址疹启、密碼和服務(wù)器地址:

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

連接POP3服務(wù)器:

server = poplib.POP3(pop3_server)
server.set_debuglevel(1)                      # 打開調(diào)式信息
print(server.getwelcome().decode('utf-8'))    # 打印POP3服務(wù)器歡迎信息

需要注意的是,如果使用的郵箱pop服務(wù)有加密蔼卡,則需要以加密的方法連接服務(wù)器喊崖,像這樣:

server = poplib.POP3_SSL(pop3_server)

進(jìn)行身份認(rèn)證:

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

返回郵箱的相關(guān)信息:

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

這里stat()可以獲取郵件總數(shù)目及占用空間。

list()可以獲取每一封郵件的編號(hào)即占用空間雇逞。

獲取一封郵件:

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

retr()可以返回郵件的全部文本荤懂,其中lines存儲(chǔ)的是文本的每一行內(nèi)容。

接下來(lái)就是解析文本的部分塘砸,后面會(huì)介紹:

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

最后關(guān)閉連接:

server.quit()

解析郵件

解析郵件的過(guò)程與構(gòu)造郵件正好相反节仿。

首先,引入必要的模塊:

from email.parser import Parser            # 解析模塊
from email.header import decode_header     # 用于獲取頭文件的編碼信息
from email.utils import pasrseaddr         # 用于格式化郵件信息

import poplib

由于在解析郵件的過(guò)程中掉蔬,會(huì)遇到編碼問(wèn)題廊宪,需要進(jìn)行相應(yīng)的解碼才能正常顯示。

所以我們需要先定義相關(guān)函數(shù)用以解碼女轿。

針對(duì)郵件的相關(guān)信息箭启,比如Subjict,name等蛉迹,我們定義一個(gè)decode_str函數(shù):

def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = valur.decode(charset)           # 如果文本中存在編碼信息册烈,則進(jìn)行相應(yīng)的解碼
    return value

針對(duì)郵件的文本內(nèi)容,我們需要檢測(cè)編碼婿禽,否則,非UTF-8編碼的郵件都無(wú)法正常顯示大猛,我們定義一個(gè)guess_charset函數(shù):

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='這個(gè)字符串
        if pos >=0:                                         # 如果有,則獲取該字符串后面的編碼信息
            charset = content_type[pos+8:].strip()
    return charset

這里lower()是把字符串全改為小寫表示挽绩。

strip()是去除字符串前后的空格字符膛壹。

準(zhǔn)備好編碼的問(wèn)題,就開始正式解析郵件吧唉堪。

把郵件內(nèi)容解析為Message對(duì)象:

msg = Parser().parsestr(msg_content)

由于這個(gè)Message對(duì)象可能嵌套著其他MIMEBase對(duì)象模聋,所以我們要遞歸地打印出Mseeage的層次結(jié)構(gòu):

def print_info(msg, indent=0):                              # indent用于縮進(jìn)顯示 
    # 首先打印郵件的發(fā)件人,收件人和主題
    if indent == 0:
        for header in ['From', 'To', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header == 'Subject':                     # 解碼主題信息
                    value = decode_str(value)
                else:                                       # 解碼發(fā)件人和收件人信息
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = u'%s <%s>' % (name, addr)
            print('%s%s: %s' % ('  '* indent, header, value))   #'  ' *indent可以打印出2*indent個(gè)空格
            
    # 將組合郵件對(duì)象分離唠亚,         
    if (msg.is_multipart()): 
        parts = msg.get_payload()                           # 拿取msg的子對(duì)象
        for n, part in enumerate(parts):
            print('%spart %s' % ('  ' * indent, n))
            print('%s--------------------' % ('  ' * indent))
            print_info(part,indent + 1)
    
    # 逐一打印郵件對(duì)象
    else: 
        content_type = msg.get_content_type()               # 獲取郵件對(duì)象格式
        if content_type == 'text/plain' or content_type == 'text/html':  # 如果為文本郵件链方,則直接打印
            content = msg.get_payload(decode=True)
            charset = guess_charset(msg)                     # 檢測(cè)編碼
            if charset:
                content = content.decode(charset)           # 解碼
            print('%sText: %s' % ('  ' * indent, content))  # 打印內(nèi)容
        else:
            print('%sAttachment: %s' % ('  ' * indent, content_type))  # 否則為附件,獲取附件信息

整理一下上面的代碼灶搜,就能用來(lái)收取郵件了祟蚀,比如有這樣一封郵件:


電子郵件6.png

我們運(yùn)行上面的代碼工窍,把顯示結(jié)果如下:

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

From: 三貝 <xxxxxx@126.com> 
To: xxxxxxxx<xxxxx@qq.com> 
Subject: POP3測(cè)試 
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 

從打印的結(jié)構(gòu)我們可以看出,這封郵件是一個(gè)MIMEMultipart罢维,分為兩部分:

第一部分又是一個(gè)MIMEMultipart淹仑,這一部分包含一個(gè)純文本格式的MIMEText和HTML格式的MIMEText

第二部分是一個(gè)Image文件肺孵。

小結(jié)

Python用POP3收取電子郵件分兩步:第一匀借,使用poplib下載郵件原始文本;第二悬槽,使用email把原始文本解析為Message對(duì)象怀吻,然后將內(nèi)容展示給用戶。


以上就是本節(jié)的全部?jī)?nèi)容初婆,感謝你的閱讀蓬坡。

下一節(jié)內(nèi)容:數(shù)據(jù)庫(kù)

有任何問(wèn)題與想法,歡迎評(píng)論與吐槽磅叛。

和博主一起學(xué)習(xí)Python吧( ̄▽ ̄)~*

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末屑咳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弊琴,更是在濱河造成了極大的恐慌兆龙,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敲董,死亡現(xiàn)場(chǎng)離奇詭異紫皇,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)腋寨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門聪铺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人萄窜,你說(shuō)我怎么就攤上這事铃剔。” “怎么了查刻?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵键兜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我穗泵,道長(zhǎng)普气,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任佃延,我火速辦了婚禮棋电,結(jié)果婚禮上茎截,老公的妹妹穿的比我還像新娘。我一直安慰自己赶盔,他們只是感情好企锌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著于未,像睡著了一般撕攒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烘浦,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天抖坪,我揣著相機(jī)與錄音,去河邊找鬼闷叉。 笑死擦俐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的握侧。 我是一名探鬼主播蚯瞧,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼品擎!你這毒婦竟也來(lái)了埋合?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤萄传,失蹤者是張志新(化名)和其女友劉穎甚颂,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秀菱,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡振诬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衍菱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贷揽。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梦碗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蓖救,我是刑警寧澤洪规,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站循捺,受9級(jí)特大地震影響斩例,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜从橘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一念赶、第九天 我趴在偏房一處隱蔽的房頂上張望础钠。 院中可真熱鬧,春花似錦叉谜、人聲如沸旗吁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)很钓。三九已至,卻和暖如春董栽,著一層夾襖步出監(jiān)牢的瞬間码倦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工锭碳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袁稽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓擒抛,卻偏偏與公主長(zhǎng)得像推汽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闻葵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容