摘要:電子郵件是怎樣實現(xiàn)傳輸?shù)墓苄咳绻ㄟ^SMTP協(xié)議译断,使用Python來發(fā)送電子郵件?
*寫在前面:為了更好的學(xué)習(xí)python德谅,博主記錄下自己的學(xué)習(xí)路程。本學(xué)習(xí)筆記基于廖雪峰的Python教程,如有侵權(quán),請告知刪除呕童。歡迎與博主一起學(xué)習(xí)Pythonヽ( ̄▽ ̄)? *
目錄
電子郵件
SMTP發(fā)送郵件
純文本郵件
帶HTML的郵件
帶附件的郵件
帶圖片的郵件
同時支持plain和HTML
SMTP加密
小結(jié)
電子郵件
email歷史悠久,直到現(xiàn)在都應(yīng)用廣泛淆珊。
在本節(jié)內(nèi)容中,將教大家使用Python發(fā)送和接收email奸汇。
在此之前先了解一下電子郵件的發(fā)送過程吧施符。
假設(shè)我們自己的郵件地址是myemail@163.com,對方的郵件地址是friend@qq.com擂找,我們在網(wǎng)易提供的163郵箱界面編寫郵件戳吝,然后發(fā)送給對方。那么贯涎,這封郵件是怎么從我方發(fā)送到對方的呢听哭?
(ps:這里的郵箱名字純屬虛構(gòu)。)
首先塘雳,我們稱用于編寫郵件的軟件或網(wǎng)頁為MUA(Mail User Agent)陆盘,即郵件用戶代理。
MUA會把郵件發(fā)送到MTA(Mail Transfer Agent)败明,即郵件傳輸代理隘马。就是email服務(wù)提供商如騰訊、網(wǎng)易等妻顶。在這里由于我們的郵箱是163郵箱酸员,所以優(yōu)先把郵件投遞到網(wǎng)易提供的MTA里蜒车。
隨后,網(wǎng)易提供的MTA把郵件發(fā)送到對方服務(wù)商提供的MTA幔嗦,這里是騰訊提供的MTA酿愧。這過程中會路過其他的MTA。
騰訊的MTA收到郵件后邀泉,把郵件投遞到最終目的地MDA(Mail Delivery Agent)嬉挡,即郵件投遞代理,在這里就是qq郵箱了呼渣。
最后棘伴,郵件會一直存放在對方地址的qq郵箱里,等待對方使用相應(yīng)的MUA進行查詢屁置。
總結(jié)一下郵件的發(fā)送過程:
發(fā)件人-->MUA-->(己方)MTA-->(其他)MTA-->(對方)MTA-->MDA<--MUA<--收件人
所以我們要通過編程實現(xiàn)電子郵件的發(fā)送與接收焊夸,對應(yīng)的就是
1.編寫MUA把郵件發(fā)送到MTA,
2.編寫MUA從MDA從接收郵件蓝角。
發(fā)郵件時阱穗,MUA和MTA使用的是SMTP協(xié)議(Simple Mail Transfer Protocol)。
收郵件時使鹅,MUA和MDA使用的是POP協(xié)議(Post Office Protocol)或IMAP協(xié)議(Internet Message Access Protocol)揪阶。
接下來,介紹如何用Python編寫電子郵件的發(fā)送與接收患朱。
SMTP發(fā)送郵件
郵件客戶端軟件在發(fā)郵件時鲁僚,會讓你先配置SMTP服務(wù)器。
同樣的我們在編寫MUA時裁厅,需要輸入郵箱地址冰沙、密碼、收件人地址信息执虹,以及登錄相對應(yīng)的SMTP服務(wù)器拓挥,比如qq郵箱就是smtp.qq.com
,163郵箱就是smtp.163.com
袋励。
需要注意的是侥啤,在編寫MUA之前,要在對應(yīng)的郵箱開啟SMTP服務(wù)茬故,開啟后會得到授權(quán)碼盖灸,這個授權(quán)碼在登錄SMTP服務(wù)器時要用到。
編寫MUA用到Python的兩個模塊:email
和smtplib
磺芭。
其中email
負責(zé)構(gòu)造郵件糠雨,smtplib
負責(zé)發(fā)送郵件。
純文本郵件
我們以最簡單的純文本郵件為例徘跪。
首先甘邀,通過MIMEText()
構(gòu)造一個純文本郵件:
from email.mime.text import MIMEText
msg = MIMEText('Hello, my friend...', 'plain', 'utf-8')
這里有三個參數(shù)琅攘,第一個參數(shù)為郵件正文,第二個參數(shù)為郵件類型松邪,傳入'plain'
表示純文本坞琴,第三個參數(shù)'utf-8'
是編碼,以保證兼容多語言逗抑。
然后剧辐,編寫用戶信息輸入部分:
from_addr = input('From: ') # 輸入郵件地址
password = input(Password: ') # 輸入密碼
to_addr = input('To: ') # 輸入收件人地址
smtp_server = input('SMPT server: ') # 輸入SMTP服務(wù)器地址
依次輸入的信息為:發(fā)件人郵箱地址、授權(quán)碼邮府、收件人地址荧关、SMTP服務(wù)器地址。
然后通過SMTP發(fā)送出去:
import smtplib
server = smtplib.SMTP(smtp_server, 25) # SMTP協(xié)議默認端口是25
server.set_debuglevel(1) # 打印和SMTP服務(wù)器交互的所有信息
server.login(from_addr, password) # 登錄SMTP服務(wù)器
server.sendmail(from_addr, [to_addr], msg.as_string()) #發(fā)郵件
server.quit()
其中set_debuglevel(1)
可以打印和SMTP服務(wù)器交互的所有信息褂傀。
login()
方法用來登錄SMTP服務(wù)器忍啤,需要輸入郵箱地址和密碼。
sendmail()
方法用來發(fā)送郵件仙辟,輸入三個參數(shù)同波,第一個參數(shù)表示郵箱地址,第二個參數(shù)是一個list
叠国,表示收件人地址未檩,可以多個;第三個參數(shù)是郵件正文粟焊,這里as_string()
是把MIMEText
對象變成str
冤狡。
執(zhí)行完整的代碼,我們就能在收件人郵箱收到這樣的郵件:
會發(fā)現(xiàn)這封郵件沒有主題项棠、發(fā)件人沒有顯示昵稱(只是顯示發(fā)件人的郵箱)筒溃,沒有收件人。
我們需要在MIMEText中添加主題沾乘、發(fā)件人、收件人的信息浑测,以形成完整的郵件:
from email.mime.text import MIMEText
from email import encoders
from email.header import Header
from email.utils import parseaddr, formataddr
import smtplib
def _format_addr(s):
name, addr = parseaddr(s) # 解析郵件地址翅阵,name為郵件人,addr為郵件地址
return formataddr((Header(name, 'utf-8').encode(), addr)) # 格式化郵件地址
from_addr = input('From: ') # 輸入郵件地址
password = input(Password: ') # 輸入密碼
to_addr = input('To: ') # 輸入收件人地址
smtp_server = input('SMPT server: ') # 輸入SMTP服務(wù)器地址
msg = MIMEText('Hello, my friend...', 'plain', 'utf-8')
msg['From'] = _format_addr('三貝 <%s>' % from_addr) # 添加發(fā)件人
msg['To'] = _format_addr('管理員 <%s>' % to_addr) # 添加收件人
msg['Subject'] = Header('SMTP測試', 'utf-8').encode() # 添加郵件主題
server = smtplib.SMTP(smtp_server, 25) # SMTP協(xié)議默認端口是25
server.set_debuglevel(1) # 打印和SMTP服務(wù)器交互的所有信息
server.login(from_addr, password) # 登錄SMPT服務(wù)器
server.sendmail(from_addr, [to_addr], msg.as_string()) #發(fā)郵件
server.quit()
其中函數(shù)_format_addr()
是用來格式化郵件地址的迁央。
發(fā)件人或收件人的顯示格式是name<addr@example.com>
掷匠,但是我們不能直接傳入這樣一個字符串,因為如果有中文的話岖圈,還要進行編碼讹语。
需要注意的是,這里的msg['To']
傳入的不是一個list
蜂科,如果有多個收件人顽决,直接用短条,
分隔即可。
這時候收到的郵件有顯示發(fā)件人才菠、收件人和主題了:
帶HTML的郵件
想要在郵件內(nèi)容中添加HTML茸时,在構(gòu)造MIMEText對象時,把HTML字符串傳進去即可赋访,像這樣:
msg = MIMEText('<html><body><h1>Hello, my friend...</h1>' +
'<p>send by <a +
'</body></html>', 'html', 'utf-8')
這里注意要把第二個參數(shù)'plain'
改為'html'
可都。
發(fā)送結(jié)果:
帶附件的郵件
想要在郵件中添加附件。首先需要構(gòu)造一個MIMEMultipart
對象表示郵件整體蚓耽,然后添加一個MIMEText
作為郵件正文渠牲,添加一個MIMEBase
對象作為附件即可:
from email.mime.multipart import MIMEMultipart # 再引入兩個必要模塊
from email.mime.base import MIMEBase
msg = MIMEMultipart() # 創(chuàng)建MIMEMultipart主體對象
msg['From'] = _format_addr('三貝 <%s>' % from_addr)
msg['To'] = _format_addr('管理員 <%s>' % to_addr)
msg['Subject'] = Header('SMTP測試', 'utf-8').encode()
msg.attach(MIMEText('Hello, my friend...', 'plain', 'utf-8'))
with open('c:/Users/Administrator/test.png', 'rb') as f: # 打開需要添加的附件
mime = MIMEBase('image', 'png', filename='test.png') # 創(chuàng)建MIMEBase對象,即附件內(nèi)容
mime.add_header('Content-disposition', 'attachment', filemane=.test.png') # 添加必要的頭文件
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-ID', '0')
mime.set_payload(f.read()) # 讀進附件的內(nèi)容
encoders.enode_base64(mime) # 用base64編碼
msg.attach(mime) # 把附件添加到主體對象中
然后步悠,按正常的郵件發(fā)送流程補充代碼即可签杈。
帶圖片的郵件
如果想要在郵件正文中顯示圖片呢?我們需要先把圖片作為附件贤徒,然后在HTML中通過引用src="cid:0"
就可以把附件作為圖片嵌入了芹壕。
msg.attach(MIMEText('<html><body><h1>Hello, my friend...</h1>' +
'<p><img src="cid:0"></p>' +
'</body></html>', 'html', 'utf-8'))
這個時候圖片不再作為附件發(fā)送,而是直接在郵件正文中顯示接奈。
如果有多張圖片踢涌,則給它們編號后,引用不同的cid:x
即可序宦。
同時支持plain和HTML
通過創(chuàng)建MIMEMultipart
對象睁壁,我們可以讓郵件內(nèi)容即支持plain
,也支持HTML
互捌。
在創(chuàng)建MIMEMultipart
時指定subtype
是alternative
:
...
...
msg = MIMEMultipart('alternative')
msg['From'] = ...
msg['To'] = ...
msg['Subject'] = ...
msg.attach(MIMEText('Hello, my friend...', 'plain', 'utf-8'))
msg.attach(MIMEText('<html><body><h1>Hello, my friend...</h1></body></html>', 'html', 'utf-8'))
...
...
一旦收件人無法查看HTML格式的郵件潘明,就會自動變?yōu)閜lain格式查看。
SMTP加密
使用標(biāo)準(zhǔn)的25端口連接SMTP服務(wù)器時秕噪,使用的是明文傳輸钳降,在發(fā)送的過程有可能被竊聽。
想要給郵件加密腌巾,添加starttls()
方法即可:
...
...
server = smtplib.SMTP(smtp_server, 25)
server.starttls()
...
...
在創(chuàng)建了SMTP
對象后遂填,立即調(diào)用starttls()
方法即可。
小結(jié)
構(gòu)造一個郵件對象就是一個Message
對象澈蝙。而文本郵件對象是MIMEText吓坚,圖像郵件對象是MIMEImage,組合郵件對象是MIMEMultipart灯荧,MIMEBase可以表示任意郵件對象礁击,它們的繼承關(guān)系如下:
Message
+- MIMEBase
+- MIMEMultipart
+- MIMENonMultipart
+- MIMEMessage
+- MIMEText
+- MIMEImage
詳細內(nèi)容可以查看官方文檔:email.mime文檔。
以上就是本節(jié)的全部內(nèi)容,感謝你的閱讀哆窿。
下一節(jié)內(nèi)容:電子郵件之 POP3收取郵件
有任何問題與想法链烈,歡迎評論與吐槽。
和博主一起學(xué)習(xí)Python吧( ̄▽ ̄)~*