参考连接: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.
待续。。。