Python使用poplib模組和smtplib模組收發電子郵件的教程
poplib模組接收郵件
python的poplib模組是用來從pop3收取郵件的,也可以說它是處理郵件的第一步。
POP3協定並不複雜,它也是採用的一問一答式的方式,你向伺服器發送一個命令,伺服器必然會回覆一個訊息。 pop3指令碼如下:
命令 poplib方法 参数 状态 描述 ----------------------------------------------------------------------------------------------- USER user username 认可 用户名,此命令与下面的pass命令若成功,将导致状态转换 PASS pass_ password 认可 用户密码 APOP apop Name,Digest 认可 Digest是MD5消息摘要 ----------------------------------------------------------------------------------------------- STAT stat None 处理 请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数 UIDL uidl [Msg#] 处理 返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的 LIST list [Msg#] 处理 返回邮件数量和每个邮件的大小 RETR retr [Msg#] 处理 返回由参数标识的邮件的全部文本 DELE dele [Msg#] 处理 服务器将由参数标识的邮件标记为删除,由quit命令执行 RSET rset None 处理 服务器将重置所有标记为删除的邮件,用于撤消DELE命令 TOP top [Msg#] 处理 服务器将返回由参数标识的邮件前n行内容,n必须是正整数 NOOP noop None 处理 服务器返回一个肯定的响应 ---------------------------------------------------------------------------------------------- QUIT quit None 更新
python的poplib也針對這些指令分別提供了對應的方法,上面在第二列裡已經標示出來。收取郵件的過程一般是:
1. 連接pop3伺服器 (poplib.POP3.__init__)
2. 傳送使用者名稱和密碼進行驗證 (poplib.POP3.user poplib.POP3.pass_)
3. 取得信箱中信件資訊 (poplib.POP3.stat)
4. 收取郵件 (poplib.POP3.retr)
5. 刪除郵件 (poplib.POP3.dele)
6. 退出 (poplib.POP3.quit)
注意的是,上面我在括號裡寫的是使用什麼方法來完成這個操作,在實際的程式碼中不能那樣寫,應該是創建poplib.POP3的對象,然後,呼叫這個對象的方法。如:
poplib.POP3.quit
應該理解為
a = poplib.POP3(host) a.quit()
下面看實際的程式碼:
#-*- encoding: gb2312 -*- import os, sys, string import poplib # pop3服务器地址 host = "pop3.163.com" # 用户名 username = "xxxxxx@163.com" # 密码 password = "xxxxxxx" # 创建一个pop3对象,这个时候实际上已经连接上服务器了 pp = poplib.POP3(host) # 设置调试模式,可以看到与服务器的交互信息 pp.set_debuglevel(1) # 向服务器发送用户名 pp.user(username) # 向服务器发送密码 pp.pass_(password) # 获取服务器上信件信息,返回是一个列表,第一项是一共有多上封邮件,第二项是共有多少字节 ret = pp.stat() print ret # 需要取出所有信件的头部,信件id是从1开始的。 for i in range(1, ret[0]+1): # 取出信件头部。注意:top指定的行数是以信件头为基数的,也就是说当取0行, # 其实是返回头部信息,取1行其实是返回头部信息之外再多1行。 mlist = pp.top(i, 0) print 'line: ', len(mlist[1]) # 列出服务器上邮件信息,这个会对每一封邮件都输出id和大小。不象stat输出的是总的统计信息 ret = pp.list() print ret # 取第一封邮件完整信息,在返回值里,是按行存储在down[1]的列表里的。down[0]是返回的状态信息 down = pp.retr(1) print 'lines:', len(down) # 输出邮件 for line in down[1]: print line # 退出 pp.quit()
在有些地方,有安全郵件這一說,其實是對pop3做了ssl加密。這樣的,poplib一樣可以處理,只不過不是用POP3這個類,而是用POP3_SSL, 他們的方法都一樣。因此支援ssl在上面程式碼中,替換創建pop3物件的一行為:
pp = poplib.POP3_SSL(host)
smtplib: 用python發送SSL/TLS安全郵件
python的smtplib提供了一個很方便的途徑發送電子郵件。它對smtp協定進行了簡單的封裝。
smtp協定的基本指令包括:
- HELO 標示伺服器使用者身分
- MAIL 初始化郵件傳送 mail from:
- RCPT 標識單一的郵件接收人;常在MAIL指令後面,可有多個rcpt to:
- DATA 在單一或多個RCPT命令後,表示所有的郵件接收人已識別,並初始化資料傳輸,以.結束
- VRFY 用來驗證指定的使用者/信箱是否存在;因安全方面的原因,伺服器常禁止此指令
- EXPN 驗證給定的郵箱清單是否存在,擴充郵箱清單,也常被停用
- HELP 查詢伺服器支援什麼指令
- NOOP 無操作,伺服器應回應OK
- QUIT 結束會話
- RSET 重置會話,目前傳送取消
- MAIL FROM 指定寄送者地址
- RCPT TO 所指的收件者位址
一般smtp會話有兩種方式,一種是郵件直接投遞,就是說,例如你要發郵件給zzz@163.com,那就直接連接163.com的郵件伺服器,把信投給zzz@ 163.com; 另一種是驗證過後的發信,它的過程是,例如你要發郵件給zzz@163.com,你不是直接投到163.com,而是透過自己在sina.com的另一個郵箱來發。這樣就要先連接sina.com的smtp伺服器,然後認證,之後在把要寄到163.com的信件投到sina.com上,sina.com會幫你把信投遞到163.com。
第一種方式的命令流程基本上是這樣:
1. helo
2. mail from
3. rcpt to
4. data
5. quit
但是第一種發送方式一般有限制的,就是rcpt to指定的這個郵件接收者必須在這個伺服器上存在,否則是不會接收的。 先看看程式碼:
#-*- encoding: gb2312 -*- import os, sys, string import smtplib # 邮件服务器地址 mailserver = "smtp.163.com" # smtp会话过程中的mail from地址 from_addr = "asfgysg@zxsdf.com" # smtp会话过程中的rcpt to地址 to_addr = "zhaoweikid@163.com" # 信件内容 msg = "test mail" svr = smtplib.SMTP(mailserver) # 设置为调试模式,就是在会话过程中会有输出信息 svr.set_debuglevel(1) # helo命令,docmd方法包括了获取对方服务器返回信息 svr.docmd("HELO server") # mail from, 发送邮件发送者 svr.docmd("MAIL FROM: <%s>" % from_addr) # rcpt to, 邮件接收者 svr.docmd("RCPT TO: <%s>" % to_addr) # data命令,开始发送数据 svr.docmd("DATA") # 发送正文数据 svr.send(msg) # 比如以 . 作为正文发送结束的标记,用send发送的,所以要用getreply获取返回信息 svr.send(" . ") svr.getreply() # 发送结束,退出 svr.quit()
注意的是,163.com是有反垃圾郵件功能的,想上面的這種投遞郵件的方法不一定能通過反垃圾郵件系統的檢測的。所以一般不建議個人這樣發送。
第二種有點不一樣:
1.ehlo
2.auth login
3.mail from
4.rcpt to
5.data
6.quit
相對於第一種來說,多了一個認證過程,就是auth login這個過程。
#-*- encoding: gb2312 -*- import os, sys, string import smtplib import base64 # 邮件服务器地址 mailserver = "smtp.163.com" # 邮件用户名 username = "xxxxxx@163.com" # 密码 password = "xxxxxxx" # smtp会话过程中的mail from地址 from_addr = "xxxxxx@163.com" # smtp会话过程中的rcpt to地址 to_addr = "yyyyyy@163.com" # 信件内容 msg = "my test mail" svr = smtplib.SMTP(mailserver) # 设置为调试模式,就是在会话过程中会有输出信息 svr.set_debuglevel(1) # ehlo命令,docmd方法包括了获取对方服务器返回信息 svr.docmd("EHLO server") # auth login 命令 svr.docmd("AUTH LOGIN") # 发送用户名,是base64编码过的,用send发送的,所以要用getreply获取返回信息 svr.send(base64.encodestring(username)) svr.getreply() # 发送密码 svr.send(base64.encodestring(password)) svr.getreply() # mail from, 发送邮件发送者 svr.docmd("MAIL FROM: <%s>" % from_addr) # rcpt to, 邮件接收者 svr.docmd("RCPT TO: <%s>" % to_addr) # data命令,开始发送数据 svr.docmd("DATA") # 发送正文数据 svr.send(msg) # 比如以 . 作为正文发送结束的标记 svr.send(" . ") svr.getreply() # 发送结束,退出 svr.quit()
上面说的是最普通的情况,但是不能忽略的是现在好多企业邮件是支持安全邮件的,就是通过SSL发送的邮件,这个怎么发呢?SMTP对SSL安全邮件的支持有两种方案,一种老的是专门开启一个465端口来接收ssl邮件,另一种更新的做法是在标准的25端口的smtp上增加一个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) # 新增加的创建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 # 设置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连接。我这里测试的192.168.2.10是我自己的测试服务器.
第二种是新增加了starttls的命令,这个很简单,smtplib里就有这个方法,叫smtplib.starttls()。当然,不是所有的邮件系统都支持安全邮件的,这个需要从ehlo的返回值里来确认,如果里面有starttls,才表示支持。相对于发送普通邮件的第二种方法来说,只需要新增加一行代码就可以了:
#-*- encoding: gb2312 -*- import os, sys, string import smtplib import base64 # 邮件服务器地址 mailserver = "smtp.163.com" # 邮件用户名 username = "xxxxxx@163.com" # 密码 password = "xxxxxxx" # smtp会话过程中的mail from地址 from_addr = "xxxxxx@163.com" # smtp会话过程中的rcpt to地址 to_addr = "yyyyyy@163.com" # 信件内容 msg = "my test mail" svr = smtplib.SMTP(mailserver) # 设置为调试模式,就是在会话过程中会有输出信息 svr.set_debuglevel(1) # ehlo命令,docmd方法包括了获取对方服务器返回信息,如果支持安全邮件,返回值里会有starttls提示 svr.docmd("EHLO server") svr.starttls() # <------ 这行就是新加的支持安全邮件的代码! # auth login 命令 svr.docmd("AUTH LOGIN") # 发送用户名,是base64编码过的,用send发送的,所以要用getreply获取返回信息 svr.send(base64.encodestring(username)) svr.getreply() # 发送密码 svr.send(base64.encodestring(password)) svr.getreply() # mail from, 发送邮件发送者 svr.docmd("MAIL FROM: <%s>" % from_addr) # rcpt to, 邮件接收者 svr.docmd("RCPT TO: <%s>" % to_addr) # data命令,开始发送数据 svr.docmd("DATA") # 发送正文数据 svr.send(msg) # 比如以 . 作为正文发送结束的标记 svr.send(" . ") svr.getreply() # 发送结束,退出 svr.quit()
注意: 以上的代码为了方便我都没有判断返回值,严格说来,是应该判断一下返回的代码的,在smtp协议中,只有返回代码是2xx或者3xx才能继续下一步,返回4xx或5xx的,都是出错了。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。
