參考連接:html
python官網imaplib: https://docs.python.org/2/library/imaplib.htmlpython
Python 用IMAP接收郵件: https://www.cnblogs.com/zixuan-zhang/p/3402825.html瀏覽器
imaplib模塊-Python操做IMAP郵件服務器: http://blog.topspeedsnail.com/archives/10311安全
關於用python 的imaplib提取本身163,qq郵箱的內容: https://blog.csdn.net/mosbest/article/details/51557988服務器
什麼是POP三、SMTP和IMAP?: http://help.163.com/09/1223/14/5R7P6CJ600753VB8.htmlless
使用python發送和接收郵件: https://www.cnblogs.com/itogo/p/5910681.htmlsocket
POP3是Post Office Protocol 3的簡稱,即郵局協議的第3個版本,它規定怎樣將我的計算機鏈接到Internet的郵件服務器和下載電子郵件的電子協議。它是因特網電子郵件的第一個離線協議標準,POP3容許用戶從服務器上把郵件存儲到本地主機(即本身的計算機)上,同時刪除保存在郵件服務器上的郵件,而POP3服務器則是遵循POP3協議的接收郵件服務器,用來接收電子郵件的。ide
SMTP 的全稱是「Simple Mail Transfer Protocol」,即簡單郵件傳輸協議。它是一組用於從源地址到目的地址傳輸郵件的規範,經過它來控制郵件的中轉方式。SMTP 協議屬於 TCP/IP 協議簇,它幫助每臺計算機在發送或中轉信件時找到下一個目的地。SMTP 服務器就是遵循 SMTP 協議的發送郵件服務器。SMTP 認證,簡單地說就是要求必須在提供了帳戶名和密碼以後才能夠登陸 SMTP 服務器,這就使得那些垃圾郵件的散播者無可乘之機。 增長 SMTP 認證的目的是爲了使用戶避免受到垃圾郵件的侵擾。post
IMAP全稱是Internet Mail Access Protocol,即交互式郵件存取協議,它是跟POP3相似郵件訪問標準協議之一。不一樣的是,開啓了IMAP後,您在電子郵件客戶端收取的郵件仍然保留在服務器上,同時在客戶端上的操做都會反饋到服務器上,如:刪除郵件,標記已讀等,服務器上的郵件也會作相應的動做。因此不管從瀏覽器登陸郵箱或者客戶端軟件登陸郵箱,看到的郵件以及狀態都是一致的。測試
核心代碼模塊
import imaplib
核心代碼模塊
核心代碼模塊
參考連接:
python smtplib email: https://www.cnblogs.com/senjougahara/p/5845475.html
python模塊之smtplib: 用python發送SSL/TLS安全郵件: http://www.cnblogs.com/sislcb/archive/2008/12/02/1345467.html
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的,都是出錯了。
3 注意事項
3.1 Does Python's imaplib let you set a timeout?
參考連接:https://stackoverflow.com/questions/24422724/does-pythons-imaplib-let-you-set-a-timeout
I'm looking at the API for Python's imaplib.
From what I can tell, there is no way to setup a timeout like you can with smtplib.
Is that correct? How would you handle a host that's invalid if you don't want it to block?
The imaplib
module doesn't provide a way to set timeout, but you can set a default timeout for new socket connections via the socket.setdefaulttimeout
:
import socket import imaplib socket.setdefaulttimeout(10) imap = imaplib.IMAP4('test.com', 666)
3.2 STARTTLS
參考連接:https://blog.csdn.net/MashiMaroJ/article/details/40980313
SSL and TLS both provide a way to encrypt a communication channel between two computers (e.g. your computer and our server). TLS is the successor to SSL and the terms SSL and TLS are used interchangeably unless you're referring to a specific version of the protocol.
STARTTLS is a way to take an existing insecure connection and upgrade it to a secure connection using SSL/TLS. Note that despite having TLS in the name, STARTTLS doesn't mean you have to use TLS, you can use SSL.
待續。。。