使用python處理郵件正文及附件

用python接收郵件的功能非常的常見(jiàn),我也研究了好久,參考了廖雪峰大大的相關(guān)教程和網(wǎng)上的一些資源才大概了解了相應(yīng)的功能。其中好多代碼是直接參考(copy)別人的旁涤,中文處理方面真的是折磨了我好久外莲。
日常生活中使用QQ郵箱的頻率很高犀斋,我在這里使用的也是QQ郵箱匾南,像以前的話囊骤,QQ郵箱的pop3登錄可以直接使用新密碼就可以直接登錄了猿涨,但現(xiàn)在我發(fā)現(xiàn)直接使用新設(shè)置的密碼會(huì)報(bào)錯(cuò)握童。

poplib.error_proto: b'-ERR Please using authorized code to login.

因此我只能使用短信的方式獲取驗(yàn)證碼。


image.png

然后使用之后的授權(quán)碼當(dāng)做密碼就不會(huì)再報(bào)錯(cuò)了叛赚。
首先是登錄郵箱

import poplib
email='392361639@qq.com'
password='授權(quán)碼'
server=poplib.POP3_SSL('pop.qq.com')
server.user(email)
server.pass_(password)
resp, mails, octets = server.list()
index = len(mails)#郵件的總數(shù)
#server.dele(index) 刪除郵件 dele可以用于刪除制定位置的郵件
resp, lines, octets = server.retr(index)#可以取出最新的郵件的信息
msg_content = b'\r\n'.join(lines).decode('utf-8','ignore')  #將郵件組合到一起澡绩,生成郵件信息
print(msg_content)
msg_content大致內(nèi)容.png

可以看到打印出來(lái)的msg_content文件信息大致是這樣的,里面包含了郵件的頭文件俺附,如Date肥卡,Subject,F(xiàn)rom事镣,TO等信息步鉴。接下來(lái)要取出郵件頭部相關(guān)的信息。上圖的頭部信息并沒(méi)有出現(xiàn)亂碼璃哟,但有的郵件就會(huì)如下圖所示


image.png
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr#專門處理地址的模塊
#email中專門處理郵件內(nèi)容的模塊
msg = Parser().parsestr(msg_content)
#通過(guò)msg.get('From')等方法可以獲取頭部氛琢,但會(huì)出現(xiàn)編碼不對(duì)
#通過(guò)decode,將Subject其變?yōu)橹形?def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value

def get_header(msg):
    for header in ['From', 'To', 'Subject']:
        value = msg.get(header, '')
        if value:
            #文章的標(biāo)題有專門的處理方法
            if header == 'Subject':
                value = decode_str(value)
            elif header in ['From','To']:
            #地址也有專門的處理方法
                hdr, addr = parseaddr(value)
                value = decode_str(addr)
        print(header + ':' + value)

頭部信息取出后接著去正文內(nèi)容随闪,由于我平時(shí)的需求主要為文本信息或者附件阳似,針對(duì)指定郵件獲取信息,或者是取出附件铐伴,對(duì)一些廣告郵件就不需要處理(我也不知道如何去處理)
郵件的正文部分處理

#郵件正文部分

#取附件
#郵件的正文部分在生成器中撮奏,msg.walk()
#如果存在附件,則可以通過(guò).get_filename()的方式獲取文件名稱
def get_file(msg):
    for part in msg.walk():
        filename=part.get_filename()
        if filename!=None:#如果存在附件
            filename = decode_str(filename)#獲取的文件是亂碼名稱当宴,通過(guò)之前定義的函數(shù)解碼
            data = part.get_payload(decode = True)#取出文件正文內(nèi)容
            #此處可以自己定義文件保存位置
            path=filename
            f = open(path, 'wb')
            f.write(data)
            f.close()
            print(filename,'download')


#接下來(lái)取正文信息

#獲取郵件的字符編碼畜吊,首先在message中尋找編碼,如果沒(méi)有户矢,就在header的Content-Type中尋找
def guess_charset(msg):
    charset = msg.get_charset()
    if charset is None:
        content_type = msg.get('Content-Type', '').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos+8:].strip()
    return charset

def get_content(msg):
    for part in msg.walk():
        content_type = part.get_content_type()
        charset = guess_charset(part)
        #如果有附件定拟,則直接跳過(guò)
        if part.get_filename()!=None:
            continue
        email_content_type = ''
        content = ''
        if content_type == 'text/plain':
            email_content_type = 'text'
        elif content_type == 'text/html':
            print('html 格式 跳過(guò)')
            continue #不要html格式的郵件
            email_content_type = 'html'
        if charset:
            try:
                content = part.get_payload(decode=True).decode(charset)
            #這里遇到了幾種由廣告等不滿足需求的郵件遇到的錯(cuò)誤,直接跳過(guò)了
            except AttributeError:
                print('type error')
            except LookupError:
                print("unknown encoding: utf-8")
        if email_content_type =='':
            continue
            #如果內(nèi)容為空逗嫡,也跳過(guò)
        print(email_content_type + ' -----  ' + content)
        #郵件的正文內(nèi)容就在content中
郵件正文結(jié)果

下面附上完整代碼

import poplib
#解析郵件
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr

#解析消息頭中的字符串
#沒(méi)有這個(gè)函數(shù)青自,print出來(lái)的會(huì)使亂碼的頭部信息。如'=?gb18030?B?yrXWpL3hufsueGxz?='這種
#通過(guò)decode驱证,將其變?yōu)橹形?def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value

#解碼郵件信息分為兩個(gè)步驟延窜,第一個(gè)是取出頭部信息
#首先取頭部信息
#主要取出['From','To','Subject']
'''
From: "=?gb18030?B?anVzdHpjYw==?=" <justonezcc@sina.com>
To: "=?gb18030?B?ztLX1Ly6tcTTys/k?=" <392361639@qq.com>
Subject: =?gb18030?B?dGV4dMTjusM=?=
'''
#如上述樣式,均需要解碼
def get_header(msg):
    for header in ['From', 'To', 'Subject']:
        value = msg.get(header, '')
        if value:
            #文章的標(biāo)題有專門的處理方法
            if header == 'Subject':
                value = decode_str(value)
            elif header in ['From','To']:
            #地址也有專門的處理方法
                hdr, addr = parseaddr(value)
                name = decode_str(addr)
                #value = name + ' < ' + addr + ' > '
                value=name
        print(header + ':' + value)
#頭部信息已取出


#獲取郵件的字符編碼抹锄,首先在message中尋找編碼逆瑞,如果沒(méi)有荠藤,就在header的Content-Type中尋找
def guess_charset(msg):
    charset = msg.get_charset()
    if charset is None:
        content_type = msg.get('Content-Type', '').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos+8:].strip()
    return charset


#郵件正文部分
#取附件
#郵件的正文部分在生成器中,msg.walk()
#如果存在附件获高,則可以通過(guò).get_filename()的方式獲取文件名稱

def get_file(msg):
    for part in msg.walk():
        filename=part.get_filename()
        if filename!=None:#如果存在附件
            filename = decode_str(filename)#獲取的文件是亂碼名稱哈肖,通過(guò)一開(kāi)始定義的函數(shù)解碼
            data = part.get_payload(decode = True)#取出文件正文內(nèi)容
            #此處可以自己定義文件保存位置
            path=filename
            f = open(path, 'wb')
            f.write(data)
            f.close()
            print(filename,'download')

def get_content(msg):
    for part in msg.walk():
        content_type = part.get_content_type()
        charset = guess_charset(part)
        #如果有附件,則直接跳過(guò)
        if part.get_filename()!=None:
            continue
        email_content_type = ''
        content = ''
        if content_type == 'text/plain':
            email_content_type = 'text'
        elif content_type == 'text/html':
            print('html 格式 跳過(guò)')
            continue #不要html格式的郵件
            email_content_type = 'html'
        if charset:
            try:
                content = part.get_payload(decode=True).decode(charset)
            except AttributeError:
                print('type error')
            except LookupError:
                print("unknown encoding: utf-8")
        if email_content_type =='':
            continue
            #如果內(nèi)容為空念秧,也跳過(guò)
        print(email_content_type + ' -----  ' + content)

#get_file(msg)
if __name__ == '__main__':
    
    email='392361639@qq.com'
    password='ngq*******rznbici'

    server=poplib.POP3_SSL('pop.qq.com')
    server.user(email)
    server.pass_(password)
    #登錄的過(guò)程
    resp, mails, octets = server.list()
    index = len(mails)#郵件的總數(shù)
    #此處的循環(huán)是取最近的幾封郵件
    for i in range(index-2,index+1):
        resp, lines, octets = server.retr(i)#取郵件
        msg_content = b'\r\n'.join(lines).decode('utf-8','ignore')
        msg = Parser().parsestr(msg_content)
        #server.dele(index) 刪除郵件
        get_header(msg)
        get_file(msg)
        get_content(msg)
    server.quit()

下面是發(fā)送正文及附件淤井,相對(duì)讀取郵件信息,發(fā)送郵件要比讀取要簡(jiǎn)單很多

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os 

sender = 'justonezcc@sina.com'
receiver = '392361639@qq.com'
subject = 'python email test'
smtpserver = 'smtp.sina.com'
password = '***'
from email import encoders
msgRoot = MIMEMultipart('alternative')

msgRoot['Subject'] = subject
msgRoot['From'] = sender
msgRoot['To']=receiver

#發(fā)送正文
content='你好摊趾,這是一封測(cè)試郵件'
cont=MIMEText(content,'plain','utf-8')
msgRoot.attach(cont)

#發(fā)送附件
file_name='實(shí)證結(jié)果.xls'#要發(fā)送文件的文字

row_path=os.getcwd()#或者其他路徑
path=os.path.join(row_path,file_name)

att = MIMEText(open(path, 'rb').read(), 'base64', 'gb2312')
att["Content-Type"] = 'application/octet-stream'
att.add_header('Content-Disposition', 'attachment', filename=('gb2312', '', file_name)) 
msgRoot.attach(att)

smtp = smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login(sender, password)
smtp.sendmail(sender, receiver, msgRoot.as_string())
smtp.quit()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末币狠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子砾层,更是在濱河造成了極大的恐慌漩绵,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肛炮,死亡現(xiàn)場(chǎng)離奇詭異止吐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)侨糟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門祟印,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人粟害,你說(shuō)我怎么就攤上這事〔遥” “怎么了悲幅?”我有些...
    開(kāi)封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)站蝠。 經(jīng)常有香客問(wèn)我汰具,道長(zhǎng),這世上最難降的妖魔是什么菱魔? 我笑而不...
    開(kāi)封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任留荔,我火速辦了婚禮,結(jié)果婚禮上澜倦,老公的妹妹穿的比我還像新娘聚蝶。我一直安慰自己,他們只是感情好藻治,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布碘勉。 她就那樣靜靜地躺著,像睡著了一般桩卵。 火紅的嫁衣襯著肌膚如雪验靡。 梳的紋絲不亂的頭發(fā)上倍宾,一...
    開(kāi)封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音胜嗓,去河邊找鬼高职。 笑死,一個(gè)胖子當(dāng)著我的面吹牛辞州,可吹牛的內(nèi)容都是我干的怔锌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼孙技,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼产禾!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起牵啦,我...
    開(kāi)封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤亚情,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后哈雏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體楞件,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年裳瘪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了土浸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彭羹,死狀恐怖黄伊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情派殷,我是刑警寧澤还最,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站毡惜,受9級(jí)特大地震影響拓轻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜经伙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一扶叉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帕膜,春花似錦枣氧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至危纫,卻和暖如春宗挥,著一層夾襖步出監(jiān)牢的瞬間乌庶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工契耿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞒大,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓搪桂,卻偏偏與公主長(zhǎng)得像透敌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子踢械,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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

  • 1 為何要發(fā)電子郵件酗电? 作為職場(chǎng)人士,想必在工作中大家都經(jīng)常收發(fā)電子郵件内列,一封高效得體的工作郵件勢(shì)必會(huì)讓溝通事半功...
    Helen_Cat閱讀 5,910評(píng)論 0 12
  • 1 為何要發(fā)電子郵件? 作為職場(chǎng)人士交排,想必在工作中大家都經(jīng)常收發(fā)電子郵件划滋,一封高效得體的工作郵件勢(shì)必會(huì)讓溝通事半功...
    嘛樣閱讀 89,619評(píng)論 14 108
  • 一处坪、郵件開(kāi)發(fā)涉及到的一些基本概念 郵件服務(wù)器和電子郵箱 郵件傳輸協(xié)議 電子郵件的發(fā)送和接收過(guò)程 1.1郵件服務(wù)器和...
    yjaal閱讀 1,452評(píng)論 0 7
  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,969評(píng)論 3 119
  • 1.感恩愉快的一天 2.感恩今天氣溫仍舊很高架专,在家穿背心同窘,出去穿單褲,給兒子也穿了單衣胶征,小孩子火力旺男孩更不能捂著...
    無(wú)極41531閱讀 422評(píng)論 0 1