Python使用poplib模塊和smtplib模塊收發(fā)電子郵件的教程
poplib模塊接收郵件
python的poplib模塊是用來從pop3收取郵件的,也可以說它是處理郵件的第一步。
POP3協(xié)議并不復(fù)雜,它也是采用的一問一答式的方式,你向服務(wù)器發(fā)送一個(gè)命令,服務(wù)器必然會(huì)回復(fù)一個(gè)信息。pop3命令碼如下:
命令 poplib方法 參數(shù) 狀態(tài) 描述 ----------------------------------------------------------------------------------------------- USER user username 認(rèn)可 用戶名,此命令與下面的pass命令若成功,將導(dǎo)致狀態(tài)轉(zhuǎn)換 PASS pass_ password 認(rèn)可 用戶密碼 APOP apop Name,Digest 認(rèn)可 Digest是MD5消息摘要 ----------------------------------------------------------------------------------------------- STAT stat None 處理 請(qǐng)求服務(wù)器發(fā)回關(guān)于郵箱的統(tǒng)計(jì)資料,如郵件總數(shù)和總字節(jié)數(shù) UIDL uidl [Msg#] 處理 返回郵件的唯一標(biāo)識(shí)符,POP3會(huì)話的每個(gè)標(biāo)識(shí)符都將是唯一的 LIST list [Msg#] 處理 返回郵件數(shù)量和每個(gè)郵件的大小 RETR retr [Msg#] 處理 返回由參數(shù)標(biāo)識(shí)的郵件的全部文本 DELE dele [Msg#] 處理 服務(wù)器將由參數(shù)標(biāo)識(shí)的郵件標(biāo)記為刪除,由quit命令執(zhí)行 RSET rset None 處理 服務(wù)器將重置所有標(biāo)記為刪除的郵件,用于撤消DELE命令 TOP top [Msg#] 處理 服務(wù)器將返回由參數(shù)標(biāo)識(shí)的郵件前n行內(nèi)容,n必須是正整數(shù) NOOP noop None 處理 服務(wù)器返回一個(gè)肯定的響應(yīng) ---------------------------------------------------------------------------------------------- QUIT quit None 更新
python的poplib也針對(duì)這些命令分別提供了對(duì)應(yīng)的方法,上面在第二列里已經(jīng)標(biāo)出來。收取郵件的過程一般是:
1. 連接pop3服務(wù)器 (poplib.POP3.__init__)
2. 發(fā)送用戶名和密碼進(jìn)行驗(yàn)證 (poplib.POP3.user poplib.POP3.pass_)
3. 獲取郵箱中信件信息 (poplib.POP3.stat)
4. 收取郵件 (poplib.POP3.retr)
5. 刪除郵件 (poplib.POP3.dele)
6. 退出 (poplib.POP3.quit)
注意的是,上面我在括號(hào)里寫的是使用什么方法來完成這個(gè)操作,在實(shí)際的代碼中不能那樣寫,應(yīng)該是創(chuàng)建poplib.POP3的對(duì)象,然后,調(diào)用這個(gè)對(duì)象的方法。比如:
poplib.POP3.quit
應(yīng)該理解為
a = poplib.POP3(host) a.quit()
下面看看實(shí)際的代碼:
#-*- encoding: gb2312 -*- import os, sys, string import poplib # pop3服務(wù)器地址 host = "pop3.163.com" # 用戶名 username = "xxxxxx@163.com" # 密碼 password = "xxxxxxx" # 創(chuàng)建一個(gè)pop3對(duì)象,這個(gè)時(shí)候?qū)嶋H上已經(jīng)連接上服務(wù)器了 pp = poplib.POP3(host) # 設(shè)置調(diào)試模式,可以看到與服務(wù)器的交互信息 pp.set_debuglevel(1) # 向服務(wù)器發(fā)送用戶名 pp.user(username) # 向服務(wù)器發(fā)送密碼 pp.pass_(password) # 獲取服務(wù)器上信件信息,返回是一個(gè)列表,第一項(xiàng)是一共有多上封郵件,第二項(xiàng)是共有多少字節(jié) ret = pp.stat() print ret # 需要取出所有信件的頭部,信件id是從1開始的。 for i in range(1, ret[0]+1): # 取出信件頭部。注意:top指定的行數(shù)是以信件頭為基數(shù)的,也就是說當(dāng)取0行, # 其實(shí)是返回頭部信息,取1行其實(shí)是返回頭部信息之外再多1行。 mlist = pp.top(i, 0) print 'line: ', len(mlist[1]) # 列出服務(wù)器上郵件信息,這個(gè)會(huì)對(duì)每一封郵件都輸出id和大小。不象stat輸出的是總的統(tǒng)計(jì)信息 ret = pp.list() print ret # 取第一封郵件完整信息,在返回值里,是按行存儲(chǔ)在down[1]的列表里的。down[0]是返回的狀態(tài)信息 down = pp.retr(1) print 'lines:', len(down) # 輸出郵件 for line in down[1]: print line # 退出 pp.quit()
在有些地方,有安全郵件這一說,其實(shí)是對(duì)pop3做了ssl加密。這樣的,poplib一樣可以處理,只不過不是用POP3這個(gè)類,而是用POP3_SSL, 他們的方法都一樣。因此支持ssl在上面代碼中,替換創(chuàng)建pop3對(duì)象的一行為:
pp = poplib.POP3_SSL(host)
smtplib: 用python發(fā)送SSL/TLS安全郵件
python的smtplib提供了一種很方便的途徑發(fā)送電子郵件。它對(duì)smtp協(xié)議進(jìn)行了簡單的封裝。
smtp協(xié)議的基本命令包括:
- HELO 向服務(wù)器標(biāo)識(shí)用戶身份
- MAIL 初始化郵件傳輸 mail from:
- RCPT 標(biāo)識(shí)單個(gè)的郵件接收人;常在MAIL命令后面,可有多個(gè)rcpt to:
- DATA 在單個(gè)或多個(gè)RCPT命令后,表示所有的郵件接收人已標(biāo)識(shí),并初始化數(shù)據(jù)傳輸,以.結(jié)束
- VRFY 用于驗(yàn)證指定的用戶/郵箱是否存在;由于安全方面的原因,服務(wù)器常禁止此命令
- EXPN 驗(yàn)證給定的郵箱列表是否存在,擴(kuò)充郵箱列表,也常被禁用
- HELP 查詢服務(wù)器支持什么命令
- NOOP 無操作,服務(wù)器應(yīng)響應(yīng)OK
- QUIT 結(jié)束會(huì)話
- RSET 重置會(huì)話,當(dāng)前傳輸被取消
- MAIL FROM 指定發(fā)送者地址
- RCPT TO 指明的接收者地址
一般smtp會(huì)話有兩種方式,一種是郵件直接投遞,就是說,比如你要發(fā)郵件給zzz@163.com,那就直接連接163.com的郵件服務(wù)器,把信投給zzz@163.com; 另一種是驗(yàn)證過后的發(fā)信,它的過程是,比如你要發(fā)郵件給zzz@163.com,你不是直接投到163.com,而是通過自己在sina.com的另一個(gè)郵箱來發(fā)。這樣就要先連接sina.com的smtp服務(wù)器,然后認(rèn)證,之后在把要發(fā)到163.com的信件投到sina.com上,sina.com會(huì)幫你把信投遞到163.com。
第一種方式的命令流程基本是這樣:
1. helo
2. mail from
3. rcpt to
4. data
5. quit
但是第一種發(fā)送方式一般有限制的,就是rcpt to指定的這個(gè)郵件接收者必須在這個(gè)服務(wù)器上存在,否則是不會(huì)接收的。 先看看代碼:
#-*- encoding: gb2312 -*- import os, sys, string import smtplib # 郵件服務(wù)器地址 mailserver = "smtp.163.com" # smtp會(huì)話過程中的mail from地址 from_addr = "asfgysg@zxsdf.com" # smtp會(huì)話過程中的rcpt to地址 to_addr = "zhaoweikid@163.com" # 信件內(nèi)容 msg = "test mail" svr = smtplib.SMTP(mailserver) # 設(shè)置為調(diào)試模式,就是在會(huì)話過程中會(huì)有輸出信息 svr.set_debuglevel(1) # helo命令,docmd方法包括了獲取對(duì)方服務(wù)器返回信息 svr.docmd("HELO server") # mail from, 發(fā)送郵件發(fā)送者 svr.docmd("MAIL FROM: <%s>" % from_addr) # rcpt to, 郵件接收者 svr.docmd("RCPT TO: <%s>" % to_addr) # data命令,開始發(fā)送數(shù)據(jù) svr.docmd("DATA") # 發(fā)送正文數(shù)據(jù) svr.send(msg) # 比如以 . 作為正文發(fā)送結(jié)束的標(biāo)記,用send發(fā)送的,所以要用getreply獲取返回信息 svr.send(" . ") svr.getreply() # 發(fā)送結(jié)束,退出 svr.quit()
注意的是,163.com是有反垃圾郵件功能的,想上面的這種投遞郵件的方法不一定能通過反垃圾郵件系統(tǒng)的檢測(cè)的。所以一般不推薦個(gè)人這樣發(fā)送。
第二種有點(diǎn)不一樣:
1.ehlo
2.auth login
3.mail from
4.rcpt to
5.data
6.quit
相對(duì)于第一種來說,多了一個(gè)認(rèn)證過程,就是auth login這個(gè)過程。
#-*- encoding: gb2312 -*- import os, sys, string import smtplib import base64 # 郵件服務(wù)器地址 mailserver = "smtp.163.com" # 郵件用戶名 username = "xxxxxx@163.com" # 密碼 password = "xxxxxxx" # smtp會(huì)話過程中的mail from地址 from_addr = "xxxxxx@163.com" # smtp會(huì)話過程中的rcpt to地址 to_addr = "yyyyyy@163.com" # 信件內(nèi)容 msg = "my test mail" svr = smtplib.SMTP(mailserver) # 設(shè)置為調(diào)試模式,就是在會(huì)話過程中會(huì)有輸出信息 svr.set_debuglevel(1) # ehlo命令,docmd方法包括了獲取對(duì)方服務(wù)器返回信息 svr.docmd("EHLO server") # auth login 命令 svr.docmd("AUTH LOGIN") # 發(fā)送用戶名,是base64編碼過的,用send發(fā)送的,所以要用getreply獲取返回信息 svr.send(base64.encodestring(username)) svr.getreply() # 發(fā)送密碼 svr.send(base64.encodestring(password)) svr.getreply() # mail from, 發(fā)送郵件發(fā)送者 svr.docmd("MAIL FROM: <%s>" % from_addr) # rcpt to, 郵件接收者 svr.docmd("RCPT TO: <%s>" % to_addr) # data命令,開始發(fā)送數(shù)據(jù) svr.docmd("DATA") # 發(fā)送正文數(shù)據(jù) svr.send(msg) # 比如以 . 作為正文發(fā)送結(jié)束的標(biāo)記 svr.send(" . ") svr.getreply() # 發(fā)送結(jié)束,退出 svr.quit()
上面說的是最普通的情況,但是不能忽略的是現(xiàn)在好多企業(yè)郵件是支持安全郵件的,就是通過SSL發(fā)送的郵件,這個(gè)怎么發(fā)呢?SMTP對(duì)SSL安全郵件的支持有兩種方案,一種老的是專門開啟一個(gè)465端口來接收ssl郵件,另一種更新的做法是在標(biāo)準(zhǔn)的25端口的smtp上增加一個(gè)starttls的命令來支持。
看看第一種怎么辦:
#-*- encoding: gb2312 -*- import os, sys, string, socket import smtplib class SMTP_SSL (smtplib.SMTP): def __init__(self, host='', port=465, local_hostname=None, key=None, cert=None): self.cert = cert self.key = key smtplib.SMTP.__init__(self, host, port, local_hostname) def connect(self, host='localhost', port=465): if not port and (host.find(':') == host.rfind(':')): i = host.rfind(':') if i >= 0: host, port = host[:i], host[i+1:] try: port = int(port) except ValueError: raise socket.error, "nonnumeric port" if not port: port = 654 if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) msg = "getaddrinfo returns an empty list" self.sock = None for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: self.sock = socket.socket(af, socktype, proto) if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) self.sock.connect(sa) # 新增加的創(chuàng)建ssl連接 sslobj = socket.ssl(self.sock, self.key, self.cert) except socket.error, msg: if self.debuglevel > 0: print>>stderr, 'connect fail:', (host, port) if self.sock: self.sock.close() self.sock = None continue break if not self.sock: raise socket.error, msg # 設(shè)置ssl self.sock = smtplib.SSLFakeSocket(self.sock, sslobj) self.file = smtplib.SSLFakeFile(sslobj); (code, msg) = self.getreply() if self.debuglevel > 0: print>>stderr, "connect:", msg return (code, msg) if __name__ == '__main__': smtp = SMTP_SSL('192.168.2.10') smtp.set_debuglevel(1) smtp.sendmail("zzz@xxx.com", "zhaowei@zhaowei.com", "xxxxxxxxxxxxxxxxx") smtp.quit()
這里我是從原來的smtplib.SMTP派生出了新的SMTP_SSL類,它專門來處理ssl連接。我這里測(cè)試的192.168.2.10是我自己的測(cè)試服務(wù)器.
第二種是新增加了starttls的命令,這個(gè)很簡單,smtplib里就有這個(gè)方法,叫smtplib.starttls()。當(dāng)然,不是所有的郵件系統(tǒng)都支持安全郵件的,這個(gè)需要從ehlo的返回值里來確認(rèn),如果里面有starttls,才表示支持。相對(duì)于發(fā)送普通郵件的第二種方法來說,只需要新增加一行代碼就可以了:
#-*- encoding: gb2312 -*- import os, sys, string import smtplib import base64 # 郵件服務(wù)器地址 mailserver = "smtp.163.com" # 郵件用戶名 username = "xxxxxx@163.com" # 密碼 password = "xxxxxxx" # smtp會(huì)話過程中的mail from地址 from_addr = "xxxxxx@163.com" # smtp會(huì)話過程中的rcpt to地址 to_addr = "yyyyyy@163.com" # 信件內(nèi)容 msg = "my test mail" svr = smtplib.SMTP(mailserver) # 設(shè)置為調(diào)試模式,就是在會(huì)話過程中會(huì)有輸出信息 svr.set_debuglevel(1) # ehlo命令,docmd方法包括了獲取對(duì)方服務(wù)器返回信息,如果支持安全郵件,返回值里會(huì)有starttls提示 svr.docmd("EHLO server") svr.starttls() # <------ 這行就是新加的支持安全郵件的代碼! # auth login 命令 svr.docmd("AUTH LOGIN") # 發(fā)送用戶名,是base64編碼過的,用send發(fā)送的,所以要用getreply獲取返回信息 svr.send(base64.encodestring(username)) svr.getreply() # 發(fā)送密碼 svr.send(base64.encodestring(password)) svr.getreply() # mail from, 發(fā)送郵件發(fā)送者 svr.docmd("MAIL FROM: <%s>" % from_addr) # rcpt to, 郵件接收者 svr.docmd("RCPT TO: <%s>" % to_addr) # data命令,開始發(fā)送數(shù)據(jù) svr.docmd("DATA") # 發(fā)送正文數(shù)據(jù) svr.send(msg) # 比如以 . 作為正文發(fā)送結(jié)束的標(biāo)記 svr.send(" . ") svr.getreply() # 發(fā)送結(jié)束,退出 svr.quit()
注意: 以上的代碼為了方便我都沒有判斷返回值,嚴(yán)格說來,是應(yīng)該判斷一下返回的代碼的,在smtp協(xié)議中,只有返回代碼是2xx或者3xx才能繼續(xù)下一步,返回4xx或5xx的,都是出錯(cuò)了。
- python email smtplib模塊發(fā)送郵件代碼實(shí)例
- Python使用email模塊對(duì)郵件進(jìn)行編碼和解碼的實(shí)例教程
- python中使用smtplib和email模塊發(fā)送郵件實(shí)例
- 用smtplib和email封裝python發(fā)送郵件模塊類分享
- python通過imaplib模塊讀取gmail里郵件的方法
- 使用Python3 poplib模塊刪除服務(wù)器多天前的郵件實(shí)現(xiàn)代碼
- 在Python中使用poplib模塊收取郵件的教程
- Python網(wǎng)絡(luò)編程之使用email、smtplib、poplib、imaplib模塊收發(fā)郵件
相關(guān)文章
python解析html提取數(shù)據(jù),并生成word文檔實(shí)例解析
這篇文章主要介紹了python解析html提取數(shù)據(jù),并生成word文檔實(shí)例解析,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01python全棧要學(xué)什么 python全棧學(xué)習(xí)路線
在本文中小編給大家整理了關(guān)于python全棧要學(xué)什么以及python全棧學(xué)習(xí)路線的知識(shí)點(diǎn)內(nèi)容,需要的朋友們參考下。2019-06-06Windows8下安裝Python的BeautifulSoup
這篇文章主要介紹了Windows8下安裝Python的BeautifulSoup,本文著重講解安裝中出現(xiàn)的錯(cuò)誤和解決方法,需要的朋友可以參考下2015-01-01Python使用requests及BeautifulSoup構(gòu)建爬蟲實(shí)例代碼
這篇文章主要介紹了Python使用requests及BeautifulSoup構(gòu)建爬蟲,介紹了具體操作步驟和實(shí)例代碼等相關(guān)內(nèi)容,小編覺得還是挺不錯(cuò)的,這里分享給大家,需要的朋友可以參考下2018-01-01