技术笔记:Indy的TIdSMTP改造,解决发送Html和主题截断问题
使用Indy来发邮件坑不少啊,只不过有比没有好吧,使用delphi6这种老工具没办法,只能使用了新一点的Indy版本9,公司限制。。。
1、邮件包含TIdText和TIdAttachment时会出现TIdText无法发送的问题
这个问题是因为Indy代码的bug导致的,也很奇怪这种Bug是因为没有经过测试呢?还是测试没有覆盖到?
问题出在SendBody方法上,这个在之前一篇中提到过《技术笔记:Indy控件发送邮件》
当时是解决“发送Html”的问题才使用到了TIdText这个组件,因为基类TIdMessageClient中的SendBody方法中如果存在TIdText和TIdAttachment时有一个Bug:
if AMsg.MessageParts.TextPartCount > 1 then
必须>1这就有问题。因为只有一个TIdText所以这句话会导致无法发送body内容。所以解决方法是再添加一个相同的TIdText,之前测试还挺好的,但昨天发现反馈有人收到的邮件中有重复的body内容。也挺奇怪,我自己测试的时候没有呢?而且试了不好邮箱都正常的。。
解决办法比较简单,就是继承TIdSMTP,重写SendBody方法。把这一句改一下:
if AMsg.MessageParts.TextPartCount >= 1 then
变成 >=吧,目前测试下来是正常的。至少在发邮件时不用再重复添加TIdText了。
2、邮件主题Subject超过一定的字符量就会出现截断
另外提求新需求要求主题增加一些内容,以便收件人可以一眼看出邮件是啥意思。挺简单的事情吧,结果发生了难过的事情。收到的邮件主题是截断的,而且后面的内容解析错误。心想这是个什么鬼。网上一找有同样的问题,原因也找到了:
【原因】Indy的IdMessage组件在生成待发送的邮件时,主题中有汉字时会按RFC2045~2047的base64编码规范对主题进行编码,base64要求编码后每行长度不能超过75(76)个字节;所以当主题过长时要分行。问题是IdMessage编码时,用了2对分行符<CR><LF><CR><LF>,而RFC规定<CR><LF><CR><LF>表示邮件中一节的结束,所以接收邮件的程序只会对第1行解码,其余的理解为邮件内容了。
可见Indy确实主要照顾了英文的使用,像中文这种复杂的点语言估计都没好好测试吧,另外以前只听说Indy问题多但一直没感觉到,现在接触多一些果然有所体会啊。当然高人也给出了解决方案,就是把这个<CR><LF><CR><LF>换成<CR><LF>这样就行了。
procedure TIdSmtpEx.SendHeader(AMsg: TIdMessage); var LHeaders: TIdHeaderList; begin LHeaders := AMsg.GenerateHeader; try //解决标题过长时导致的收件方解码错误问题 LHeaders.Text := StringReplace(LHeaders.Text, #13#10#13#10, #13#10, [rfReplaceAll]); WriteStrings(LHeaders); finally FreeAndNil(LHeaders); end; end;
#13#10就是回车和换行的意思,对应<CR><LF>
测试下来发现是正确的。
代码已经放到gitbub上:https://github.com/mini188/IndyMail