一次邮件发送协议SMTP问题排查
项目中需要用到smtp协议来发送邮件告警,后端的技术栈主要是Java和C++,Java项目里直接在网上找的现成的类完美实现,163邮箱,腾讯邮箱和阿里邮箱均测试通过,不幸的是C++的项目也需要使用smtp协议来发送邮件,惯例先度娘,CSDN逛了一圈,例程也不少但是每个下边留言都有这样和那样的问题,copy过来直接运行,163邮箱完美测试通过,我们用的钉钉全家桶,测试钉钉邮箱时发现不能发送邮件,认证都有问题。好吧,还是先老老实实的学习遍SMTP协议吧
WireShark抓取一次完整的邮件交互过程(关闭ssl):
流程如下:
第一步:发送EHLO指令,申明身份,表示自己身份需要验证,注意这部分需要通过Telnet验证一下,是user@example.com还是user,否则会出错。
第二步:发送AUTH LOGIN指令,登录邮箱,这一部分一般要用base64加密。
第三步:发送MAIL指令,这个命令用来开始传送邮件,它的后面跟随发件方邮件地址(返回邮件地址)。它也用来当邮件无法送达时,发送失败通知。为保证邮件的成功发送,发件方的地址应是被对方或中间转发方同意接受的。这个命令会清空有关的缓冲区,为新的邮件做准备。
第四步:发送RCPT指令,这个命令告诉收件方收件人的邮箱。当有多个收件人时,需要多次使用该命令RCPT TO,每次只能指明一个人。如果接收方服务器不同意转发这个地址的邮件,它必须报550错误代码通知发件方。如果服务器同意转发,它要更改邮件发送路径,把最开始的目的地(该服务器)换成下一个服务器。
第五步:发送DATA指令,收件方把该命令之后的数据作为发送的数据。数据被加入数据缓冲区中,以单独一行是”.”的行结束数据。结束行对于接收方同时意味立即开始缓冲区内的数据传送,传送结束后清空缓冲区。如果传送接受,接收方回复OK。
第六步:发送QUIT指令,SMTP要求接收放必须回答OK,然后中断传输;在收到这个命令并回答OK前,收件方不得中断连接,即使传输出现错误。发件方在发出这个命令并收到OK答复前,也不得中断连接。
分析:
掌握了基本的流程和抓取了数据包,只要C++也按照这种数据格式发送即可,认证不通过,首先怀疑用户名和密码传输的数据有问题,抓取C++发送的数据包,果然User数据BASE64的值不一样,Pass的值是一样的,解Base64后发现一个是user@example.com,一个是user,显然问题出在这,163邮箱要求是user,钉钉邮箱要求是user@example.com,改正后认证成功,接着发送邮件也OK,完事大吉,然而。。。一周后项目完成交给测试人员,告诉我告警邮件发不过来,怎么可能,运行工程,打脸了,只能发送一次,接着就发不出去邮件了,难道钉钉给屏蔽了,Java测试了下,没问题,好吧,继续抓包,认证是没问题的,发送过去就是收不到。
Java发送抓取的DATA数据部分如下:
C++发送抓取的DATA数据部分如下:
很明显差别太大了,From,To的格式不对,Content-Type也不对,但是明显差别的是少了Message-ID字段,所以重点先分析Message-ID,又抓取了多次比对后每次的Message-ID都是不同的,怀疑这给C++只能发送一次成功有关系,C++中增加了如下代码:
email = "From: ";
email += user;
email += "\r\n";
email += "To: ";
email += targetAddr;
email += "\r\n";
//新增
email += "Message-ID: ";
email += “1”;
email += "\r\n";
email += "Subject: ";
email += title;
email += "\r\n";
email += "MIME-Version: 1.0";
email += "\r\n";
email += "Content-Type: multipart/mixed;boundary=qwertyuiop";
email += "\r\n";
email += "\r\n";
运行果然成功了,但是在运行又不成功了,把Message-ID值改为2又成功了,问题果然出在这里,大功告成,最终Message-ID改为:机器名+随机数。
总结:
WireShark是个很好的工具,善于使用它分析网络传输协议,抓包能够说明一切,让问题一目了然。
原文发布时间为:2018-10-19
本文作者:蜗牛
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
实践 | Sentinel 扩展性设计
Sentinel 提供多样的 SPI 接口用于提供扩展的能力。用户可以在用同一个 sentinel-core 的基础上自行扩展接口实现,从而可以方便地给 Sentinel 添加自定义的逻辑。 初始化逻辑扩展机制 为了统一初始化的流程,我们抽象出了 InitFunc 接口代表 Sentinel 的一些初始化逻辑,如: 注册动态规则源(示例) 注册 StatisticSlot 回调函数(示例) 启动 Command Center 初始化心跳发送 我们可以通过注解设置 InitFunc 执行的优先级。当应用首次访问资源时,注册的初始化函数会依次执行。若希望手动提前触发初始化,可以在相应的位置(如 Spring Bean)调用 InitExecutor.doInit() 函数,重复调用只会执行一次。 Slot Chain 扩展机制 Sentinel 内部是
- 下一篇
Redis 5.0 正式发布!一网打尽所有新特性!
作为一统缓存江山的redis,正式发布了5.0稳定版(stable),激不激动,开不开森?Github链接:https://github.com/antirez/redis/releases/tag/5.0.0 ,让我们一起看看它带来了哪些振奋人心的新特性: 官方列举特性如下: Redis开源社区版新特性 下面我们对一些重要特性进行更深入的了解。 Streams 全新的数据类型:Streams。官方把这个当做是最重要的改进(The most important user facing improvement iswithout doubtsthe introduction of the new general purpose data type after years: the streams. )。而且官方提到在发版本的几个小时前还在修复streams的问题,所以官方也不敢保证release版本是否有一些比较严重的BUG(T T),官方还是建议大家在生产环境不要使用streams,这样可能会有更好的体验,扎心了(People not using the streams can hav...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS关闭SELinux安全模块
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长