Python網(wǎng)絡(luò)編程之使用email、smtplib、poplib、imaplib模塊收發(fā)郵件
一封電子郵件的旅程是:
- MUA:Mail User Agent——郵件用戶代理。(即類似Outlook的電子郵件軟件)
- MTA:Mail Transfer Agent——郵件傳輸代理,就是那些Email服務(wù)提供商,比如網(wǎng)易、新浪等等。
- MDA:Mail Delivery Agent——郵件投遞代理。Email服務(wù)提供商的某個服務(wù)器
發(fā)件人 -> MUA -> MTA -> MTA -> 若干個MTA -> MDA <- MUA <- 收件人
要編寫程序來發(fā)送和接收郵件,本質(zhì)上就是:
- 編寫MUA把郵件發(fā)到MTA;
- 編寫MUA從MDA上收郵件。
發(fā)郵件時,MUA和MTA使用的協(xié)議就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一個MTA也是用SMTP協(xié)議。
收郵件時,MUA和MDA使用的協(xié)議有兩種:POP:Post Office Protocol,目前版本是3,俗稱POP3;IMAP:Internet Message Access Protocol,目前版本是4,優(yōu)點(diǎn)是不但能取郵件,還可以直接操作MDA上存儲的郵件,比如從收件箱移到垃圾箱,等等。
一、SMTP(Simple Mail Transfer Protocol)
即簡單郵件傳輸協(xié)議,它是一組用于由源地址到目的地址傳送郵件的規(guī)則,由它來控制信件的中轉(zhuǎn)方式。
python的smtplib提供了一種很方便的途徑發(fā)送電子郵件。它對smtp協(xié)議進(jìn)行了簡單的封裝。
Python對SMTP支持有smtplib
和email
兩個模塊,email
負(fù)責(zé)構(gòu)造郵件,smtplib
負(fù)責(zé)發(fā)送郵件。
1、構(gòu)造郵件:email.mime類型
構(gòu)造一個郵件對象就是一個Messag
對象,如果構(gòu)造一個MIMEText
對象,就表示一個文本郵件對象,如果構(gòu)造一個MIMEImage
對象,就表示一個作為附件的圖片,要把多個對象組合起來,就用MIMEMultipart
對象,而MIMEBase
可以表示任何對象。它們的繼承關(guān)系如下:
Message +- MIMEBase +- MIMEMultipart +- MIMENonMultipart +- MIMEMessage +- MIMEText +- MIMEImage
首先,我們來構(gòu)造一個最簡單的純文本郵件,然后,通過SMTP發(fā)出去。
from email.mime.text import MIMEText msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
注意到構(gòu)造MIMEText
對象時,第一個參數(shù)就是郵件正文,第二個參數(shù)是MIME的subtype,傳入'plain'
,最終的MIME就是'text/plain'
,最后一定要用utf-8
編碼保證多語言兼容性。
2、創(chuàng)建 SMTP 對象
語法如下:
import smtplib smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
參數(shù)說明:
- host: SMTP 服務(wù)器主機(jī)。 你可以指定主機(jī)的ip地址或者域名如: runoob.com,這個是可選參數(shù)。
- port: 如果你提供了 host 參數(shù), 你需要指定 SMTP 服務(wù)使用的端口號,一般情況下 SMTP 端口號為25。
- local_hostname: 如果 SMTP 在你的本機(jī)上,你只需要指定服務(wù)器地址為 localhost 即可。
3、Python SMTP 對象使用 sendmail 方法發(fā)送郵件
語法如下:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
參數(shù)說明:
- from_addr: 郵件發(fā)送者地址。
- to_addrs: 字符串列表,郵件發(fā)送地址。
- msg: 發(fā)送消息
這里要注意一下第三個參數(shù),msg 是字符串,表示郵件。我們知道郵件一般由標(biāo)題,發(fā)信人,收件人,郵件內(nèi)容,附件等構(gòu)成,發(fā)送郵件的時候,要注意 msg 的格式。這個格式就是 smtp 協(xié)議中定義的格式。
二、實(shí)例
2:本機(jī)已安裝支持 SMTP 的服務(wù)
以下執(zhí)行實(shí)例需要你本機(jī)已安裝了支持 SMTP 的服務(wù)。
sendmail()
方法就是發(fā)郵件,由于可以一次發(fā)給多個人,所以傳入一個list
,郵件正文是一個str
,as_string()
把MIMEText
對象變成str
。
經(jīng)過Header
對象編碼的文本,包含utf-8編碼信息和Base64編碼的文本。
以下是一個使用 Python 發(fā)送郵件簡單的實(shí)例:
import smtplib from email.mime.text import MIMEText from email.header import Header sender = 'from@runoob.com' receivers = ['429240967@qq.com'] # 接收郵件,可設(shè)置為你的QQ郵箱或者其他郵箱 # 三個參數(shù):第一個為文本內(nèi)容,第二個 plain 設(shè)置文本格式,第三個 utf-8 設(shè)置編碼 message = MIMEText('Python 郵件發(fā)送測試內(nèi)容...', 'plain', 'utf-8') message['From'] = Header("菜鳥教程", 'utf-8') # 發(fā)送者 message['To'] = Header("測試", 'utf-8') # 接收者 message['Subject'] = Header('Python SMTP 郵件測試主題', 'utf-8') try: smtpObj = smtplib.SMTP('localhost') smtpObj.sendmail(sender, receivers, message.as_string()) print "郵件發(fā)送成功" except smtplib.SMTPException: print "Error: 無法發(fā)送郵件"
2、使用第三方 SMTP 服務(wù)
如果我們本機(jī)沒有 sendmail 訪問,也可以使用其他郵件服務(wù)商的 SMTP 訪問(QQ、網(wǎng)易、Google等)。
login()
方法用來登錄SMTP服務(wù)器
發(fā)收件件人的名字沒有顯示為友好的名字,比如Mr Green
;
使用 formataddr方法來格式化一個郵件地址。如果包含中文,需要通過Header
對象進(jìn)行編碼。
msg['To']
接收的是字符串而不是list,如果有多個郵件地址,用,
分隔即可。
import smtplib from email.mime.text import MIMEText from email.utils import formataddr # 第三方 SMTP 服務(wù) mail_host = "mail.sss.com" # 設(shè)置服務(wù)器 mail_user = "it_system@sss.com" # 用戶名 mail_pass = "Ssss201709#" # 口令 sender = 'it_system@tcl.com' receivers = 'sss.yang@tcsssl.com' # 接收郵件,可設(shè)置為你的QQ郵箱或者其他郵箱 message = MIMEText('Python 郵件內(nèi)容測試...', 'plain', 'utf-8') message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('楊生', receivers)) message['Subject'] = 'Python SMTP 郵件測試' try: smtpObj = smtplib.SMTP() smtpObj.connect(mail_host, 25) # 25 為 SMTP 端口號 smtpObj.login(mail_user, mail_pass) smtpObj.sendmail(sender, receivers, message.as_string()) print("郵件發(fā)送成功") except smtplib.SMTPException: print("Error: 無法發(fā)送郵件")
3、使用Python發(fā)送HTML格式的郵件
Python在構(gòu)造MIMEText
對象時,把HTML字符串傳進(jìn)去,再把第二個參數(shù)由plain
變?yōu)?code>html就可以了:
具體代碼如下:
mail_msg = """ Python 郵件內(nèi)容測試... 這是一個鏈接 """ message = MIMEText(mail_msg, 'html', 'utf-8')
4、Python 發(fā)送帶附件的郵件
帶附件的郵件可以看做包含若干部分的郵件:文本和各個附件本身,所以,可以構(gòu)造一個MIMEMultipart
對象代表郵件本身,然后往里面加上一個MIMEText
作為郵件正文,再繼續(xù)往里面加上表示附件的MIMEBase
對象即可。
發(fā)送帶附件的郵件,首先要創(chuàng)建MIMEMultipart()實(shí)例,然后構(gòu)造附件,如果有多個附件,可依次構(gòu)造,最后利用smtplib.smtp發(fā)送。
from email.mime.multipart import MIMEMultipart # 創(chuàng)建一個帶附件的實(shí)例 message = MIMEMultipart() message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('楊生', receivers)) message['Subject'] = 'Python SMTP 郵件測試' mail_msg = """ Python 郵件內(nèi)容測試... 這是一個鏈接 """ # 郵件正文內(nèi)容 message.attach(MIMEText(mail_msg, 'html', 'utf-8')) # 構(gòu)造附件1,傳送當(dāng)前目錄下的 test.txt 文件 att = MIMEText(open('32.txt', 'rb').read(), 'base64', 'utf-8') att["Content-Type"] = 'application/octet-stream' # 這里的filename可以任意寫,寫什么名字,郵件中顯示什么名字 att["Content-Disposition"] = 'attachment; filename="32.txt"' message.attach(att)
5、在 HTML 文本中添加圖片
要把圖片嵌入到郵件正文中,我們只需按照發(fā)送附件的方式,先把郵件作為附件添加進(jìn)去,然后,在HTML中通過引用src="cid:0"
就可以把附件作為圖片嵌入了。如果有多個圖片,給它們依次編號,然后引用不同的cid:x
即可。
郵件的 HTML 文本中一般郵件服務(wù)商添加外鏈?zhǔn)菬o效的,正確添加圖片的實(shí)例如下所示:
from email.mime.multipart import MIMEMultipart from email.mime.image import MIMEImage # 創(chuàng)建一個帶附件的實(shí)例 message = MIMEMultipart() message['From'] = formataddr(('SCBC-啊iT', sender)) message['To'] = formataddr(('楊生', receivers)) message['Subject'] = 'Python SMTP 郵件測試' mail_msg = """ Python 郵件內(nèi)容測試... 這是一個鏈接 圖片演示: """ # 郵件正文內(nèi)容 message.attach(MIMEText(mail_msg, 'html', 'utf-8')) # 指定圖片為當(dāng)前目錄 with open('a.jpg', 'rb') as fp: msgImage = MIMEImage(fp.read()) # 定義圖片 ID,在 HTML 文本中引用 msgImage.add_header('Content-ID', '') message.attach(msgImage)
或者通過MIMEBase來添加圖片
# 指定圖片為當(dāng)前目錄 with open('a.jpg', 'rb') as fp: # 設(shè)置附件的MIME和文件名,這里是png類型: mime = MIMEBase('image', 'jpg', filename='a.jpg') # 加上必要的頭信息: mime.add_header('Content-Disposition', 'attachment', filename='附件顯示名稱.jpg') mime.add_header('Content-ID', '') # 如果有多個文件需要使用.format(index) mime.add_header('X-Attachment-Id', '0') # 如果有多個文件需要使用.format(index) # 把附件的內(nèi)容讀進(jìn)來: mime.set_payload(fp.read()) # 用Base64編碼: encoders.encode_base64(mime) # 添加到MIMEMultipart: message.attach(mime)
6、同時支持HTML和Plain格式
如果我們發(fā)送HTML郵件,收件人通過瀏覽器或者Outlook之類的軟件是可以正常瀏覽郵件內(nèi)容的,但是,如果收件人使用的設(shè)備太古老,查看不了HTML郵件怎么辦?
辦法是在發(fā)送HTML的同時再附加一個純文本,如果收件人無法查看HTML格式的郵件,就可以自動降級查看純文本郵件。
利用MIMEMultipart
就可以組合一個HTML和Plain,要注意指定subtype是alternative
:
msg = MIMEMultipart('alternative') msg['From'] = ... msg['To'] = ... msg['Subject'] = ... msg.attach(MIMEText('hello', 'plain', 'utf-8')) msg.attach(MIMEText('Hello', 'html', 'utf-8')) # 正常發(fā)送msg對象...
7、加密SMTP
使用標(biāo)準(zhǔn)的25端口連接SMTP服務(wù)器時,使用的是明文傳輸,發(fā)送郵件的整個過程可能會被竊聽。要更安全地發(fā)送郵件,可以加密SMTP會話,實(shí)際上就是先創(chuàng)建SSL安全連接,然后再使用SMTP協(xié)議發(fā)送郵件。
某些郵件服務(wù)商,例如Gmail,提供的SMTP服務(wù)必須要加密傳輸。我們來看看如何通過Gmail提供的安全SMTP發(fā)送郵件。
只需要在創(chuàng)建SMTP
對象后,立刻調(diào)用starttls()
方法,就創(chuàng)建了安全連接。后面的代碼和前面的發(fā)送郵件代碼完全一樣。
必須知道,Gmail的SMTP端口是587,因此,修改代碼如下:
smtp_server = 'smtp.gmail.com' smtp_port = 587 server = smtplib.SMTP(smtp_server, smtp_port) server.starttls() # 剩下的代碼和前面的一模一樣: server.set_debuglevel(1)
三、使用poplib接收郵件
收取郵件就是編寫一個MUA作為客戶端,從MDA把郵件獲取到用戶的電腦或者手機(jī)上。收取郵件最常用的協(xié)議是POP協(xié)議,目前版本號是3,俗稱POP3。
Python內(nèi)置一個poplib
模塊,實(shí)現(xiàn)了POP3協(xié)議,可以直接用來收郵件。
POP3 的命令和響應(yīng)數(shù)據(jù)都是基于 ASCII 文本的,并以 CR 和 LF(/r/n) 作為行結(jié)束符,響應(yīng)數(shù)據(jù)包括一個表示返回狀態(tài)的符號(+/)和描述信息。
請求和響應(yīng)的標(biāo)準(zhǔn)格式如下:
請求標(biāo)準(zhǔn)格式:命令 [參數(shù)] CRLF
響應(yīng)標(biāo)準(zhǔn)格式:+OK /[-ERR] description CRLF
POP3 協(xié)議客戶端的命令和服務(wù)器端對應(yīng)的響應(yīng)數(shù)據(jù)如下:
- user name:向 POP 服務(wù)器發(fā)送登錄的用戶名。
- pass string:向 POP 服務(wù)器發(fā)送登錄的密碼。
- quit:退出 POP 服務(wù)器。
- stat:統(tǒng)計郵件服務(wù)器狀態(tài),包括郵件數(shù)和總大小。
- list [msg_no]:列出全部郵件或指定郵件。返回郵件編號和對應(yīng)大小。
- retr msg_no:獲取指定郵件的內(nèi)容(根據(jù)郵件編號來獲取,編號從 1 開始)。
- dele msg_no:刪除指定郵件(根據(jù)郵件編號來刪除,編號從 1 開始)。
- noop:空操作。僅用于與服務(wù)器保持連接。
- rset:用于撤銷 dele 命令。
poplib 模塊完全模擬了上面命令,poplib.POP3 或 poplib.POP3_SSL 為上面命令提供了相應(yīng)的方法,開發(fā)者只要依次使用上面命令即可從服務(wù)器端下載對應(yīng)的郵件
注意到POP3協(xié)議收取的不是一個已經(jīng)可以閱讀的郵件本身,而是郵件的原始文本,這和SMTP協(xié)議很像,SMTP發(fā)送的也是經(jīng)過編碼后的一大段文本。
要把POP3收取的文本變成可以閱讀的郵件,還需要用email
模塊提供的各種類來解析原始文本,變成可閱讀的郵件對象。
所以,收取郵件分兩步:
第一步:使用poplib.POP3 或 poplib.POP3_SSL 按 POP3 協(xié)議把郵件的原始文本下載到本地;
用POP3獲取郵件其實(shí)很簡單,要獲取所有郵件,只需要循環(huán)使用retr()
把每一封郵件內(nèi)容拿到即可。真正麻煩的是把郵件的原始內(nèi)容解析為可以閱讀的郵件對象。
import poplib from email.parser import Parser # email.parser 解析電子郵件,返回這個對象的email.message.Message實(shí)例 from email.header import decode_header from email.utils import parseaddr # 服務(wù)器及用戶信息 host = 'mail.tcl.com' username = 'bobin.yang@tcl.com' password = 'Ybb7654321' # 連接到POP3服務(wù)器 conn = poplib.POP3_SSL(host) # 注意qq郵箱使用SSL連接 # 設(shè)置調(diào)試模式,可以看到與服務(wù)器的交互信息 conn.set_debuglevel(1) # 打印POP3服務(wù)器的歡迎文字 print(conn.getwelcome().decode("utf-8")) # 身份認(rèn)證 conn.user(username) conn.pass_(password) # 獲取服務(wù)器上信件信息,返回一個列表,第一項(xiàng)是一共有多少封郵件,第二項(xiàng)是共有多少字節(jié) # stat()返回郵件數(shù)量和占用空間 mail_total, total_size = conn.stat() print('message: %s.Size:%s' % (mail_total, total_size)) # list()返回(response, ['mesg_num octets', ...], octets),第二項(xiàng)是編號 resp, mails, octets = conn.list() print(mails) # 返回的列表類似[b'1 82923', b'2 2184', ...] # 獲取最新一封郵件,注意索引號從1開始 # POP3.retr(which) 檢索序號which的這個郵件,然后設(shè)置他的出現(xiàn)標(biāo)志 返回(response, ['line', ...], octets)這個三元組 resp, lines, ocetes = conn.retr(len(mails)) print('lines:', len(lines)) # lines 存儲了郵件的原始文本的每一行 # 可以獲得整個郵件的原始文本 print("-------------------")
第二步:使用 email.parser.Parser或BytesParser 解析郵件內(nèi)容為消息
對象,然后,用適當(dāng)?shù)男问桨燕]件內(nèi)容展示給用戶即可。
解析郵件的過程和上一節(jié)構(gòu)造郵件正好相反。
程序在創(chuàng)建 BytesParser(解析字節(jié)串格式的郵件數(shù)據(jù))或 Parser(解析字符串格式的郵件數(shù)據(jù))時,必須指定 policy=default
;否則,BytesParse 或 Parser 解析郵件數(shù)據(jù)得到的就是過時的 Message 對象,,不是新的 EmailMessage,處理起來非常不方便。
1、使用 email.parser.Parser解析郵件內(nèi)容為 email.message.Message(過時,不推薦)
msg = b'\r\n'.join(lines).decode('utf-8') # 解析出郵件 msg = Parser().parsestr(msg) # email.Parser.parsestr(text, headersonly=False) # 與parser()方法類似,不同的是他接受一個字符串對象而不是一個類似文件的對象 # 可選的headersonly表示是否在解析玩標(biāo)題后停止解析,默認(rèn)為否 # 返回根消息對象 # 編碼處理,文本郵件的內(nèi)容也是str,還需要檢測編碼,否則,非UTF-8編碼的郵件都無法正常顯示 def guess_charset(msg): charset = msg.get_charset() # 從msg對象獲取編碼 if charset is None: content_type = msg.get('Content-Type', '').lower() # 如果獲取不到,再從content—type字段獲取 if 'charset' in content_type: charset = content_type.split('charset=')[1].strip() return charset return charset # 數(shù)據(jù)解碼,郵件的Subject或者Email中包含的名字都是經(jīng)過編碼后的str,要正常顯示,就必須decode def decode_str(s): value, charset = decode_header(s)[0] # 數(shù)據(jù),數(shù)據(jù)編碼方式,from email.header import decode_header # decode_header()返回一個list,因?yàn)橄馛c、Bcc這樣的字段可能包含多個郵件地址,所以解析出來的會有多個元素。上面的代碼我們偷了個懶,只取了第一個元素。 if charset: value = value.decode(charset) return value # print_ingo函數(shù):解析郵件與構(gòu)造郵件的步驟正好相反 def print_info(msg, indent=0): # indent用于縮進(jìn)顯示 if indent == 0: for header in ['From', 'To', 'Subject']: # 郵件的from、to、subject存在于根對象上 value = msg.get(header, '') if value: if header == 'Subject': value = decode_str(value) # 需要解碼subject字符串 else: # 解碼mail地址 hdr, addr = parseaddr(value) name = decode_str(hdr) value = '%s' % addr print('%s: %s %s' % (header, value, name)) print('-*-' * 20) if msg.is_multipart(): # 如果郵件對象是一個is_multipart,get_payload()返回一個list,包含所有子對象 parts = msg.get_payload() # 循環(huán)獲得列表項(xiàng) for n, part in enumerate(parts): # print('%spart %s' % (' ' * indent, n)) # print('%s------------' % (' ' * indent)) # 遞歸打印沒一個子對象 print_info(part, indent + 1) else: # 郵件對象不是一個is_multipart,就根據(jù)content_type判斷 content_type = msg.get_content_type() # 數(shù)據(jù)類型 if content_type == 'text/plain' or content_type == 'text/html': # 純文本 html文本 # 純文本或html內(nèi)容 content = msg.get_payload(decode=True) # 獲得文本對象的字符串而非對象本身 charset = guess_charset(msg) # 要檢測文本編碼 if charset: content = content.decode(charset) content = '%s' % (content) print(content) # 獲取郵件文本內(nèi)容,如果只有文本,打印顯示的結(jié)果和郵件中看的效果一模一樣 else: print(content_type+'不是文本') print_info(msg, 0) # 退出 conn.quit()
2、使用email.parser.BytesParser 解析成email.message.EmailMessage對象
如果程序要獲取郵件的發(fā)件人、收件人和主題,直接通過 EmailMessage 的相應(yīng)屬性來獲取即可,與前面為 EmailMessage 設(shè)置發(fā)件人、收件人和主題的方式是對應(yīng)的。
如果程序要讀取 EmailMessage 的各部分,則需要調(diào)用該對象的 walk() 方法,該方法返回一個可迭代對象,程序使用 for 循環(huán)遍歷 walk() 方法的返回值,對郵件內(nèi)容進(jìn)行逐項(xiàng)處理:
- 如果郵件某項(xiàng)的 maintype 是 'multipart',則說明這一項(xiàng)是容器,用于包含郵件內(nèi)容、附件等其他項(xiàng)。
- 如果郵件某項(xiàng)的 maintype 是 'text',則說明這一項(xiàng)的內(nèi)容是文本,通常就是郵件正文或文本附件。對于這種文本內(nèi)容,程序直接將其輸出到控制臺中。
- 如果郵件某項(xiàng)的 maintype 是其他,則說明這一項(xiàng)的內(nèi)容是附件,程序?qū)⒏郊?nèi)容保存在本地文件中。
import os import poplib import mimetypes from email.parser import Parser, BytesParser from email.policy import default msg_data = b'\r\n'.join(lines) # 將字符串內(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('第一個收件人名字:' + msg['to'].addresses[0].username) print('第一個發(fā)件人名字:' + msg['from'].addresses[0].username) for part in msg.walk(): counter = 1 # 如果maintype是multipart,說明是容器(用于包含正文、附件等) if part.get_content_maintype() == 'multipart': continue # 如果maintype是multipart,說明是郵件正文部分 elif part.get_content_maintype() == 'text': print(part.get_content()) # 處理附件 else: # 獲取附件的文件名 filename = part.get_filename() # 如果沒有文件名,程序要負(fù)責(zé)為附件生成文件名 if not filename: # 根據(jù)附件的contnet_type來推測它的后綴名 ext = mimetypes.guess_extension(part.get_content_type()) # 如果推測不出后綴名 if not ext: # 使用.bin作為后綴名 ext = '.bin' # 程序?yàn)楦郊砩晌募? filename = 'part-%03d%s' % (counter, ext) counter += 1 # 將附件寫入的本地文件 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()
四、利用imaplib讀取郵件文本內(nèi)容及附件內(nèi)容
通過IMAP協(xié)議來管理郵箱用的,稱作交互郵件訪問協(xié)議。
! encoding:utf8 ''' 環(huán)境: Win10 64位 Python 2.7.5 參考: http://www.pythonclub.org/python-network-application/email-format http://blog.sina.com.cn/s/blog_4deeda2501016eyf.html ''' import imaplib import email def parseHeader(message): """ 解析郵件首部 """ subject = message.get('subject') h = email.Header.Header(subject) dh = email.Header.decode_header(h) subject = unicode(dh[0][0], dh[0][1]).encode('gb2312') # 主題 print subject print ' ' # 發(fā)件人 print 'From:', email.utils.parseaddr(message.get('from'))[1] print ' ' # 收件人 print 'To:', email.utils.parseaddr(message.get('to'))[1] print ' ' # 抄送人 print 'Cc:',email.utils.parseaddr(message.get_all('cc'))[1] def parseBody(message): """ 解析郵件/信體 """ # 循環(huán)信件中的每一個mime的數(shù)據(jù)塊 for part in message.walk(): # 這里要判斷是否是multipart,是的話,里面的數(shù)據(jù)是一個message 列表 if not part.is_multipart(): charset = part.get_charset() # print 'charset: ', charset contenttype = part.get_content_type() # print 'content-type', contenttype name = part.get_param("name") #如果是附件,這里就會取出附件的文件名 if name: # 有附件 # 下面的三行代碼只是為了解碼象=?gbk?Q?=CF=E0=C6=AC.rar?=這樣的文件名 fh = email.Header.Header(name) fdh = email.Header.decode_header(fh) fname = dh[0][0] print '附件名:', fname # attach_data = par.get_payload(decode=True) # 解碼出附件數(shù)據(jù),然后存儲到文件中 # try: # f = open(fname, 'wb') #注意一定要用wb來打開文件,因?yàn)楦郊话愣际嵌M(jìn)制文件 # except: # print '附件名有非法字符,自動換一個' # f = open('aaaa', 'wb') # f.write(attach_data) # f.close() else: #不是附件,是文本內(nèi)容 print part.get_payload(decode=True) # 解碼出文本內(nèi)容,直接輸出來就可以了。 # pass # print '+'*60 # 用來區(qū)別各個部分的輸出 def getMail(host, username, password, port=993): try: serv = imaplib.IMAP4_SSL(host, port) except Exception, e: serv = imaplib.IMAP4(host, port) serv.login(username, password) serv.select() # 搜索郵件內(nèi)容 typ, data = serv.search(None, '(FROM "xx@xxx.com")') count = 1 pcount = 1 for num in data[0].split()[::-1]: typ, data = serv.fetch(num, '(RFC822)') text = data[0][1] message = email.message_from_string(text) # 轉(zhuǎn)換為email.message對象 parseHeader(message) print ' ' parseBody(message) pcount += 1 if pcount > count: break serv.close() serv.logout() if __name__ == '__main__': host = "imap.mail_serv.com" # "pop.mail_serv.com" username = "Trevor@mail_serv.com" password = "your_password" getMail(host, username, password)
到此這篇關(guān)于Python收發(fā)郵件的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python實(shí)現(xiàn)簡單自動評論自動點(diǎn)贊自動關(guān)注腳本
這篇文章主要為大家介紹了Python實(shí)現(xiàn)簡單自動評論自動點(diǎn)贊自動關(guān)注腳本,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Python利用splinter實(shí)現(xiàn)瀏覽器自動化操作方法
今天小編就為大家分享一篇Python利用splinter實(shí)現(xiàn)瀏覽器自動化操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05Python設(shè)計模式之職責(zé)鏈模式原理與用法實(shí)例分析
這篇文章主要介紹了Python設(shè)計模式之職責(zé)鏈模式,結(jié)合具體實(shí)例形式分析了Python責(zé)任鏈模式的概念、原理、定義與使用方法,需要的朋友可以參考下2019-01-01淺談Tensorflow 動態(tài)雙向RNN的輸出問題
今天小編就為大家分享一篇淺談Tensorflow 動態(tài)雙向RNN的輸出問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01利用Python實(shí)現(xiàn)一個簡單的Web匯率計算器
Dash?是一個用于構(gòu)建基于?Web?的應(yīng)用程序的?Python?庫,無需?JavaScript?。本文將利用Dash編寫一個簡單的Web匯率計算器,感興趣的可以了解一下2022-08-08python使用UDP實(shí)現(xiàn)客戶端和服務(wù)器對話
這篇文章主要為大家介紹了python使用UDP實(shí)現(xiàn)客戶端和服務(wù)器對話示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03