IMAP协议从网易邮箱的骚操作到QQ邮箱的BUG

摘要:
前言本文主要是记录一下在使用IMAP协议访问网易邮箱时遇到的一个很常见的问题以及之后我如何解决并一步一步发现QQ邮箱BUG的过程。我们选用的方式是采用IMAP协议进行读取。但第一个问题有点出乎意料,测试方式很简单,分别向网易邮箱和QQ邮箱发送不支持的命令,看一下是否会影响接下来的使用即可。QQ邮箱服务器主动断开了跟我的链接。网易邮箱的抛出异常,我可以直接捕获跳过即可,对程序主流程无影响。
前言
本文主要是记录一下在使用 IMAP 协议访问网易邮箱时遇到的一个很常见的问题以及之后我如何解决并一步一步发现 QQ 邮箱 BUG 的过程。
发现问题
由于工作需要,开发的系统中需要访问用户设置的邮箱内的邮件列表。我们选用的方式是采用 IMAP 协议进行读取。简化后的代码如下:
importimaplib

client = imaplib.IMAP4_SSL(host="imap.163.com", port=993)
client.login("username", "password")
client.select()
一般邮箱都没有问题,但访问网易邮箱时,select 命令返回的结果是:
#('NO', [b'SELECT Unsafe Login. Please contact kefu@188.com for help'])
解决问题

原因分析

首先,百度一下很容易就知道答案,此处不赘述。可参考文章最后的引用链接
简述一下就是:
网易邮箱服务器会检查 IMAP 客户端有没有发送 ID 命令来表名自己的身份,如果没有,则拒绝访问。
关于 ID 命令,ID 命令的设计初衷是为了让服务器可以统计不同客户端的使用情况,但并非强制的。
协议中明确表示,服务器不得以 ID 命令内的信息而对客户端拒绝提供服务。
详细内容可参见 RFC2971 的定义:https://datatracker.ietf.org/doc/html/rfc2971

解决方案

原因知道之后,解决方案其实很简单,登陆之后再发送一个ID命令就好了。代码示例如下:
importimaplib
imaplib.Commands["ID"] = "NONAUTH"
client = imaplib.IMAP4_SSL(host="imap.163.com", port=993)
client.login("username", "password")
client._simple_command("ID",'("name" "test" "version" "0.0.1")')
client.select()
引申一下
解决方案很简单,但总感觉不够完美,少了点啥。
在实际应用中,是需要考虑用户会访问不同的邮箱的,那么就需要考虑以下两个问题:
  1. 是否有可能某些邮箱服务器不支持 ID 命令?
  2. 如果邮箱支持 ID 命令,但并不强制使用,会对其他正常功能有影响吗?
第一个问题,这个我觉得应该是有的,毕竟 ID 并非标准协议中的一部分,有可能某些邮箱服务器开发的比较早并且无人维护了吧.
所以针对这种情况是需要测试 IMAP 对于不认识的命令是如何处理的。
第二个问题,应该是不会有影响的,不过简单测试一下以求个安心。
于是,我先试了一下 QQ 邮箱。
先说第二个问题的测试结果,QQ 邮箱是没有啥影响的,这个也不重要,跳过就好。
但第一个问题有点出乎意料,测试方式很简单,分别向网易邮箱和 QQ 邮箱发送不支持的命令,看一下是否会影响接下来的使用即可。代码如下:
importimaplib

imaplib.Debug = 100imaplib.Commands["XXX"] = "NONAUTH"
host = "imap.163.com"
#host = "imap.qq.com"
client = imaplib.IMAP4_SSL(host=host, port=993)
client._simple_command("XXX", '("name" "aaa")')
client.select()
其中网易邮箱在接收到未知命令时,返回结果是:
#b'PMGB1 BAD command not support'

日志如图

IMAP协议从网易邮箱的骚操作到QQ邮箱的BUG第1张
这个符合预期,直接捕获一下异常即可。
但 QQ 邮箱在接收到未知命令时,返回的结果是:
#b'* BAD Command!'

日志如图

IMAP协议从网易邮箱的骚操作到QQ邮箱的BUG第2张
且代码在这里直接卡住了,等待几分钟后:
#ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
QQ 邮箱服务器主动断开了跟我的链接。
WTF !!!
网易邮箱的抛出异常,我可以直接捕获跳过即可,对程序主流程无影响。但 QQ 邮箱卡在这里是啥意思???
为了搞清楚这个事情,又开始了对代码卡住的分析。
代码分析过程不赘述,各种断点调试一通,最终发现,代码卡在了等待邮箱服务器返回数据的部分。
但从调试日志中可以看到,QQ 邮箱服务器已经返回了数据:b'* BAD Command!' 为啥还要等呢?难道数据有问题?
然后又是一通搜索,在 IMAP RFC3501 定义得到了答案,其中 2.2.1 节定义了邮箱服务端的返回数据格式规范:
返回数据的第一部分应该是 tag、*、+ 其中之一。
  • tag 是客户端在发送命令时携带的一个唯一标识,主要用于客户端区分收到的响应是那个命令的响应
  • * 代表此命令的相应内容尚未完结,应继续等待后续响应
  • + 代表服务端继续等待客户端发送尚未发送完的命令
因此,这里 QQ 邮箱返回的 b'* BAD Command!' 是不对的,应该是 b'tag BAD Command!'。
至此,感觉已经没有什么可做的事情了。不过,我还是给 QQ 邮箱发了封邮件,简单描述了一下问题,也不知道他们改不改,等结果吧。。。
然后我的应用代码改成了:
importimaplib

client = imaplib.IMAP4_SSL(host="imap.163.com", port=993)
client.login("username", "password")
typ, dat =client.select()
if typ != "OK":
    try:
        client._simple_command("ID", '("name" "test" "version" "0.0.1")')
    exceptException as e:
        print(e)
    typ, dat =client.select()
    if typ != "OK":
        raise Exception("邮箱登录失败: {} {}".format(typ, dat))
后记
待回复
不相关知识点整理
  • POP3 可以认为是只读的协议,客户端内的操作不会影响到服务端,只用来下载邮件
  • IMAP 是双向的协议,客户端的操作会反馈到服务端上,服务端也同步进行操作,不仅可以下载邮件,还可以删除,移动邮件,但不能发送邮件
  • SMTP 是用来发送邮件的
参考文档
IMAP4 ID 扩展https://datatracker.ietf.org/doc/html/rfc2971
IMAP4https://www.rfc-editor.org/rfc/inline-errata/rfc3501.html
第三方邮件客户端收取163邮件问题https://www.cnblogs.com/chjbbs/p/9858672.html
IMAP 与 POP3 有什么不同?http://help.163.com/10/0203/17/5UK7GVU100753VB9.html?servCode=6020251
什么是POP3、SMTP及IMAP?https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac21b87735d7227c217
imap连接提示Unsafe Login,被阻止的收信行为https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac211b1978002df8b23
Python解决的办法https://blog.csdn.net/jony_online/article/details/108638571

免责声明:文章转载自《IMAP协议从网易邮箱的骚操作到QQ邮箱的BUG》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇算法第二章上机实践报告c-3:位运算:位运算基本用法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

很有用的系统命令和一些技巧(只列出扩展名为msc和cpl的)

在开始--运行输入命令即可运行相关的命令 下面目前在windows server2003测试过,其它操作系统未测试 azman.msc    授权管理器certmgr.msc  证书ciadv.msc    索引服务compmgmt.msc 计算机管理dcpol.msc    默认域控制器安全设置devmgmt.msc  设备管理器dfrg.msc    ...

js,jq,php使用正则方法

1.js使用正则表达式案例: <script> var str=”543535364565@qq.com”; var res=“/^d*@(QQ|qq|136).(com|cn)$/”; var result=res.exec(str); alert(result); </script> 2.php使用正则表达式案例: $em...

批处理文件——多个QQ一键登录

       偶然看到有的同学登录PC的QQ,发现他有很多QQ,每登录一个要切换一个,虽然记住了密码,但还是不方便,于是想通过批处理来实现“一键登录”的功能。以下内容为本文假想,如有雷同,实属巧合!        具体的实现步骤如下:        (1)首先,查看QQ安装时的文档位置(用于保存用户登录历史记录),我的是:C:UsersDavidDocum...

获取QQ有效授权码操作步骤详解

             获取QQ有效授权码操作步骤详解                                      作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 一.登录QQ并打开QQ邮箱 1>.在QQ界面上打开QQ邮箱的Logo 2>.点击"设置",再点击"账户" 3>.查看"POP3/SMTP"...

Meteor + node-imap(nodejs) + mailparser(nodejs) 实现完整收发邮件

版本信息: Meteor:windows MIS安装  0.6.4 node-imap:npm指定的0.8.0版,不是默认的0.7.x版。 mailparser:npm安装0.3.6 以下是记录踩到的坑: 1. 使用meteor的email来发送邮件时,设置process.env.MAIL_URL要注意,如果你的gmail账号是自己设置了domain的,如...

.NET Core+QQ第三方授权登录

安装包 dotnet add package AspNet.Security.OAuth.QQ 接上文GitHub第三方授权登录 申请过程不介绍了,申请者资料,个人也是可以申请成功的。 这时候有二个参数就是clientid clientsecret APP ID:xxxx APP Key:xxxxxx 其中平台信息,这个申请审核通过后,不要修改,千万不...