【初步分析】确定是IdMessage生成邮件时截断了主题。用IdMessage->SaveToFile()获得的邮件如下:
////////////////////////////////////////////////////////////////
From: shen.js@163.com
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
To: shen.js@163.com
Content-Type: text/html
Date: Tue, 27 Apr 2004 17:35:38 +0800
test
////////////////////////////////////////////////////////////////
subject后面的第一行为主题的未截断部分,第二行为空行,第三行为主题的被截断部分,并且在收到的邮件中以乱码(就是上面的 =?GB2312?B?suLK1LLiytQ2?=)形式被放到了内容中,第四行的To: shen.js@163.com等也被放到了邮件内容中。
如果主题字节数少于45byte,则正常!
18 个解决方案
#1
的确是这样,估计是主题不允许太长。
我想,你应当给indy公司去个email.
我想,你应当给indy公司去个email.
#2
不清楚
#3
郁闷......
正在做的一个税务群发软件,主题一般都很长,要求主题不能被截断
哪位大侠知道除了indy9,其他indy版本是否也这么随意地截断主题啊?
或者有没有其他发邮件的组件好用?
//bow
正在做的一个税务群发软件,主题一般都很长,要求主题不能被截断
哪位大侠知道除了indy9,其他indy版本是否也这么随意地截断主题啊?
或者有没有其他发邮件的组件好用?
//bow
#4
up
#5
今天又测试了一下,发现问题好像出在这里:IdMessage一定把Subject按MiME标准Encode,而接收邮件的服务器不能按MIME标准正确地Decode。
1)按rfc2047的规定,邮件主题Encode后的格式
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
是正确的。
2)如果在任何邮件服务器上手工自己给自己发邮件(不用自己的程序),不管主题多长都没问题,但是有一个区别,这种情况下收到的主题并没有被Encode!!!查看信件原文时可知。
因此,现在的问题变为:
使用IdMessage时,怎样能够不加密主题?试了NoEncode=true(缺省false),根本不起作用!
1)按rfc2047的规定,邮件主题Encode后的格式
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
是正确的。
2)如果在任何邮件服务器上手工自己给自己发邮件(不用自己的程序),不管主题多长都没问题,但是有一个区别,这种情况下收到的主题并没有被Encode!!!查看信件原文时可知。
因此,现在的问题变为:
使用IdMessage时,怎样能够不加密主题?试了NoEncode=true(缺省false),根本不起作用!
#6
请哪位大侠指点一下啊。使用IdMessage遇到的问题重新描述一下:
(1)当邮件主题是有中文时会对主题编码;
(2)当主题较长时,会像上面那样分割编码;
(3)而现在很多邮件服务器或邮件程序只会对主题分割后的第1段解码并作为邮件主题,其他部分放到邮件内容中,并且不解码
(4)使用任何邮箱(比如网易、新浪等)手工互相发送邮件,主题可以任意长度,因为它们发送时不对主题进行Base64编码
因此
(1)用IdMessage怎样才能不对主题进行编码?
(2)或用什么其他组件能完成这种功能?
再送100分求救!
//bow
(1)当邮件主题是有中文时会对主题编码;
(2)当主题较长时,会像上面那样分割编码;
(3)而现在很多邮件服务器或邮件程序只会对主题分割后的第1段解码并作为邮件主题,其他部分放到邮件内容中,并且不解码
(4)使用任何邮箱(比如网易、新浪等)手工互相发送邮件,主题可以任意长度,因为它们发送时不对主题进行Base64编码
因此
(1)用IdMessage怎样才能不对主题进行编码?
(2)或用什么其他组件能完成这种功能?
再送100分求救!
//bow
#7
base64编码规则行长75,长了要截断换行
#8
老大,既然base64规定行长75,那为什么那些邮件服务器和邮件程序,包括foxmail,都只对主题的第1行解码,其他行就不理了呢?郁闷中.......
#9
用TIdMessage->SaveToFile()和LoadFromFile()测试发现:
主题第二行不解码的原因是:TIdMessage用Base64编码生成主题时,回车换行符'\0d\0a'重复了,即'\0d\0a\0d\0a'。只要去掉1个就能够正常显示了。
现在的问题是:TIdMessage好像没有提供方法去直接更改它生成的Email!只能读不能写!各位老大有什么办法没有啊?
主题第二行不解码的原因是:TIdMessage用Base64编码生成主题时,回车换行符'\0d\0a'重复了,即'\0d\0a\0d\0a'。只要去掉1个就能够正常显示了。
现在的问题是:TIdMessage好像没有提供方法去直接更改它生成的Email!只能读不能写!各位老大有什么办法没有啊?
#10
我也遇到同样问题
有些网站服务器并不对主题加密,比如tom,com
有些网站服务器并不对主题加密,比如tom,com
#11
我正想了解如何发送邮件,可否发送代码到我的邮箱:lzfhope@163.com
#12
我也想要一份
maplechen@163.com
maplechen@163.com
#13
用IdSMTP和IdMessage组件发邮件的方法就是参考雨中漫步的经典范例^_^精华区有的
整个程序较大,就不发过来了。
整个程序较大,就不发过来了。
#14
呵呵,把我的解决方法帖出来,虽然说有点土,但是管用。能不能把点数加给自己啊^_^
【问题】用Indy9的IdSMTP和IdMessage组件发送邮件,当邮件主题包含汉字并且长度较长时,会发生主题截断的现象,并且被截断的未解码的主题会放到邮件内容中
【原因】Indy的IdMessage组件在生成待发送的邮件时,主题中有汉字时会按RFC2045~2047的base64编码规范对主题进行编码,base64要求编码后每行长度不能超过75(76)个字节;所以当主题过长时要分行。问题是IdMessage编码时,用了2对分行符<CR><LF><CR><LF>,而RFC规定<CR><LF><CR><LF>表示邮件中一节的结束,所以接收邮件的程序只会对第1行解码,其余的理解为邮件内容了。
【解决办法】因为IdMessage没有提供直接修改编码后的邮件的方法,所以用IdMessage的SaveFromStream()和LoadFromStream()以及TStringList和TMemoryStream来去掉Email的Header部分多余的<CR><LF>。
感觉此方法笨了些,贴出来抛砖引语,看还有什么其他简单的办法。当然直接修改Indy的源代码最好,但俺不会delphi。真不方便,sigh~
//---------------------------------------------------------------------------
int __fastcall SMTP_SendMail(TIdSMTP* Smtp,TIdMessage *MsgSend,const TMailInfo& MI,String& sMsg)
{
//发送邮件
//注:发送的SMTP属性通过SMTP_Setup()函数设置了
//参数:
//in:
//Smtp:使用的IdSmtp控件
//MsgSend:使用的IdMessage控件
//MI:要发送的邮件信息
// OUT:
// Msg 返回错误信息
//返回值
//0: 成功发送
//-1:发送失败,参见Msg信息
//-2:连接失败,参见Msg信息
String s,sFile;
TStringList * slst = new TStringList;
//清除,否则包含有上一条的信息
MsgSend->Clear();
//是否要求收到回执
if (MI.bReturnReciept)
{//{We set the recipient to the From E-Mail address }
MsgSend->ReceiptRecipient->Text = MsgSend->From->Text;
}
else
{// {indicate that there is no receipt recipiant}
MsgSend->ReceiptRecipient->Text = "";
}
//发件人
MsgSend->From->Text = MI.sFrom;
//收件人
MsgSend->Recipients->EMailAddresses = MI.sTo; //{ To: header }
//邮件主题
MsgSend->Subject = MI.sSubject; //{ Subject: header }
//抄送
MsgSend->CCList->EMailAddresses = MI.sCc;// {CC}
//暗送
MsgSend->BccList->EMailAddresses = MI.sBcc; //{BCC}
//邮件优先级别
MsgSend->Priority = TIdMessagePriority(MI.tPriority);
//邮件内容类型
MsgSend->ContentType = MI.sContType;
MsgSend->Encoding = meUU;
//下面的一段代码解决这个bug
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////处理Header,去掉多余的CRLF
TMemoryStream* pms = new TMemoryStream();
MsgSend->SaveToStream(pms);
slst->Clear();
pms->Position = 0;
slst->LoadFromStream(pms);
for(int i=0;i<slst->Count;i++)
{
if(slst->Strings[i]=="")
{
slst->Delete(i);
}
}
slst->Add(""); //IdMessage的LoadFromStream()规定Stream必须以//<CR><LF><CR><LF>结尾
pms->Size = 0;
pms->Position = 0;
slst->SaveToStream(pms);
pms->Position = 0;
MsgSend->LoadFromStream(pms,true);
delete pms;
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//邮件内容
MsgSend->Body->Text = MI.sBody;
//附件
if(MI.sAttachList.Length() > 0)
{
slst->Clear();
slst->CommaText = MI.sAttachList;
for(int i=0;i<slst->Count;i++)
{
MsgSend->MessageParts->Add();
new TIdAttachment(MsgSend->MessageParts,slst->Strings[i]);//由第1句MsgSend->Clear()回收
}
}
delete slst;
sFile = s + "_2.eml";
// MsgSend->SaveToFile(sFile);
//连接SMTP服务器
if(!Smtp->Connected())
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
if(Smtp->ClosedGracefully)
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
//发送邮件
if(Smtp->Connected())
{
try
{
Smtp->Send(MsgSend);
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 发送邮件失败!";
sMsg += "From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,30);
sMsg += "......,";
sMsg += " [错误信息]:";
sMsg += s;
try
{
Smtp->CheckForGracefulDisconnect(true);
}
catch(...)
{
return -2;
}
try
{
Smtp->CheckForDisconnect(true,false);
}
catch(...)
{
return -2;
}
return -1;
}
}
else
{
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:连接断开!";
return -2;
}
// if(m_Para.bDebug)
{
sMsg = "成功发送邮件 From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,100);
sMsg += "......";
}
return 0;
}
【问题】用Indy9的IdSMTP和IdMessage组件发送邮件,当邮件主题包含汉字并且长度较长时,会发生主题截断的现象,并且被截断的未解码的主题会放到邮件内容中
【原因】Indy的IdMessage组件在生成待发送的邮件时,主题中有汉字时会按RFC2045~2047的base64编码规范对主题进行编码,base64要求编码后每行长度不能超过75(76)个字节;所以当主题过长时要分行。问题是IdMessage编码时,用了2对分行符<CR><LF><CR><LF>,而RFC规定<CR><LF><CR><LF>表示邮件中一节的结束,所以接收邮件的程序只会对第1行解码,其余的理解为邮件内容了。
【解决办法】因为IdMessage没有提供直接修改编码后的邮件的方法,所以用IdMessage的SaveFromStream()和LoadFromStream()以及TStringList和TMemoryStream来去掉Email的Header部分多余的<CR><LF>。
感觉此方法笨了些,贴出来抛砖引语,看还有什么其他简单的办法。当然直接修改Indy的源代码最好,但俺不会delphi。真不方便,sigh~
//---------------------------------------------------------------------------
int __fastcall SMTP_SendMail(TIdSMTP* Smtp,TIdMessage *MsgSend,const TMailInfo& MI,String& sMsg)
{
//发送邮件
//注:发送的SMTP属性通过SMTP_Setup()函数设置了
//参数:
//in:
//Smtp:使用的IdSmtp控件
//MsgSend:使用的IdMessage控件
//MI:要发送的邮件信息
// OUT:
// Msg 返回错误信息
//返回值
//0: 成功发送
//-1:发送失败,参见Msg信息
//-2:连接失败,参见Msg信息
String s,sFile;
TStringList * slst = new TStringList;
//清除,否则包含有上一条的信息
MsgSend->Clear();
//是否要求收到回执
if (MI.bReturnReciept)
{//{We set the recipient to the From E-Mail address }
MsgSend->ReceiptRecipient->Text = MsgSend->From->Text;
}
else
{// {indicate that there is no receipt recipiant}
MsgSend->ReceiptRecipient->Text = "";
}
//发件人
MsgSend->From->Text = MI.sFrom;
//收件人
MsgSend->Recipients->EMailAddresses = MI.sTo; //{ To: header }
//邮件主题
MsgSend->Subject = MI.sSubject; //{ Subject: header }
//抄送
MsgSend->CCList->EMailAddresses = MI.sCc;// {CC}
//暗送
MsgSend->BccList->EMailAddresses = MI.sBcc; //{BCC}
//邮件优先级别
MsgSend->Priority = TIdMessagePriority(MI.tPriority);
//邮件内容类型
MsgSend->ContentType = MI.sContType;
MsgSend->Encoding = meUU;
//下面的一段代码解决这个bug
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////处理Header,去掉多余的CRLF
TMemoryStream* pms = new TMemoryStream();
MsgSend->SaveToStream(pms);
slst->Clear();
pms->Position = 0;
slst->LoadFromStream(pms);
for(int i=0;i<slst->Count;i++)
{
if(slst->Strings[i]=="")
{
slst->Delete(i);
}
}
slst->Add(""); //IdMessage的LoadFromStream()规定Stream必须以//<CR><LF><CR><LF>结尾
pms->Size = 0;
pms->Position = 0;
slst->SaveToStream(pms);
pms->Position = 0;
MsgSend->LoadFromStream(pms,true);
delete pms;
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//邮件内容
MsgSend->Body->Text = MI.sBody;
//附件
if(MI.sAttachList.Length() > 0)
{
slst->Clear();
slst->CommaText = MI.sAttachList;
for(int i=0;i<slst->Count;i++)
{
MsgSend->MessageParts->Add();
new TIdAttachment(MsgSend->MessageParts,slst->Strings[i]);//由第1句MsgSend->Clear()回收
}
}
delete slst;
sFile = s + "_2.eml";
// MsgSend->SaveToFile(sFile);
//连接SMTP服务器
if(!Smtp->Connected())
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
if(Smtp->ClosedGracefully)
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
//发送邮件
if(Smtp->Connected())
{
try
{
Smtp->Send(MsgSend);
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 发送邮件失败!";
sMsg += "From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,30);
sMsg += "......,";
sMsg += " [错误信息]:";
sMsg += s;
try
{
Smtp->CheckForGracefulDisconnect(true);
}
catch(...)
{
return -2;
}
try
{
Smtp->CheckForDisconnect(true,false);
}
catch(...)
{
return -2;
}
return -1;
}
}
else
{
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:连接断开!";
return -2;
}
// if(m_Para.bDebug)
{
sMsg = "成功发送邮件 From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,100);
sMsg += "......";
}
return 0;
}
#15
呵呵我用的是BCB.感觉还是用delphi好啊,可以直接改VCL,sigh
#16
我也在写收发邮件,如果有人愿意交流请加我的QQ:84560912或MSN:sunseave@hotmail.com
#17
我也遇见类似的问题了,不过不是发生邮件发送过程中,而是接受过程中。
从某些服务器接收的邮件标题无法还原为汉字,直接把base64编码格式显示出来了,如下:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
看来也是标题过长的原因?
现在仍然束手无策
从某些服务器接收的邮件标题无法还原为汉字,直接把base64编码格式显示出来了,如下:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
看来也是标题过长的原因?
现在仍然束手无策
#18
如果像楼上某位搂主所言,那倒不如直接空格替换中间的某段字符。
如:
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
用空格替换如下字符串,就可以了
?=
=?GB2312?B?
我试过的,替换后,有一个空格同样能正确解码。
如:
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
用空格替换如下字符串,就可以了
?=
=?GB2312?B?
我试过的,替换后,有一个空格同样能正确解码。
#1
的确是这样,估计是主题不允许太长。
我想,你应当给indy公司去个email.
我想,你应当给indy公司去个email.
#2
不清楚
#3
郁闷......
正在做的一个税务群发软件,主题一般都很长,要求主题不能被截断
哪位大侠知道除了indy9,其他indy版本是否也这么随意地截断主题啊?
或者有没有其他发邮件的组件好用?
//bow
正在做的一个税务群发软件,主题一般都很长,要求主题不能被截断
哪位大侠知道除了indy9,其他indy版本是否也这么随意地截断主题啊?
或者有没有其他发邮件的组件好用?
//bow
#4
up
#5
今天又测试了一下,发现问题好像出在这里:IdMessage一定把Subject按MiME标准Encode,而接收邮件的服务器不能按MIME标准正确地Decode。
1)按rfc2047的规定,邮件主题Encode后的格式
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
是正确的。
2)如果在任何邮件服务器上手工自己给自己发邮件(不用自己的程序),不管主题多长都没问题,但是有一个区别,这种情况下收到的主题并没有被Encode!!!查看信件原文时可知。
因此,现在的问题变为:
使用IdMessage时,怎样能够不加密主题?试了NoEncode=true(缺省false),根本不起作用!
1)按rfc2047的规定,邮件主题Encode后的格式
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
是正确的。
2)如果在任何邮件服务器上手工自己给自己发邮件(不用自己的程序),不管主题多长都没问题,但是有一个区别,这种情况下收到的主题并没有被Encode!!!查看信件原文时可知。
因此,现在的问题变为:
使用IdMessage时,怎样能够不加密主题?试了NoEncode=true(缺省false),根本不起作用!
#6
请哪位大侠指点一下啊。使用IdMessage遇到的问题重新描述一下:
(1)当邮件主题是有中文时会对主题编码;
(2)当主题较长时,会像上面那样分割编码;
(3)而现在很多邮件服务器或邮件程序只会对主题分割后的第1段解码并作为邮件主题,其他部分放到邮件内容中,并且不解码
(4)使用任何邮箱(比如网易、新浪等)手工互相发送邮件,主题可以任意长度,因为它们发送时不对主题进行Base64编码
因此
(1)用IdMessage怎样才能不对主题进行编码?
(2)或用什么其他组件能完成这种功能?
再送100分求救!
//bow
(1)当邮件主题是有中文时会对主题编码;
(2)当主题较长时,会像上面那样分割编码;
(3)而现在很多邮件服务器或邮件程序只会对主题分割后的第1段解码并作为邮件主题,其他部分放到邮件内容中,并且不解码
(4)使用任何邮箱(比如网易、新浪等)手工互相发送邮件,主题可以任意长度,因为它们发送时不对主题进行Base64编码
因此
(1)用IdMessage怎样才能不对主题进行编码?
(2)或用什么其他组件能完成这种功能?
再送100分求救!
//bow
#7
base64编码规则行长75,长了要截断换行
#8
老大,既然base64规定行长75,那为什么那些邮件服务器和邮件程序,包括foxmail,都只对主题的第1行解码,其他行就不理了呢?郁闷中.......
#9
用TIdMessage->SaveToFile()和LoadFromFile()测试发现:
主题第二行不解码的原因是:TIdMessage用Base64编码生成主题时,回车换行符'\0d\0a'重复了,即'\0d\0a\0d\0a'。只要去掉1个就能够正常显示了。
现在的问题是:TIdMessage好像没有提供方法去直接更改它生成的Email!只能读不能写!各位老大有什么办法没有啊?
主题第二行不解码的原因是:TIdMessage用Base64编码生成主题时,回车换行符'\0d\0a'重复了,即'\0d\0a\0d\0a'。只要去掉1个就能够正常显示了。
现在的问题是:TIdMessage好像没有提供方法去直接更改它生成的Email!只能读不能写!各位老大有什么办法没有啊?
#10
我也遇到同样问题
有些网站服务器并不对主题加密,比如tom,com
有些网站服务器并不对主题加密,比如tom,com
#11
我正想了解如何发送邮件,可否发送代码到我的邮箱:lzfhope@163.com
#12
我也想要一份
maplechen@163.com
maplechen@163.com
#13
用IdSMTP和IdMessage组件发邮件的方法就是参考雨中漫步的经典范例^_^精华区有的
整个程序较大,就不发过来了。
整个程序较大,就不发过来了。
#14
呵呵,把我的解决方法帖出来,虽然说有点土,但是管用。能不能把点数加给自己啊^_^
【问题】用Indy9的IdSMTP和IdMessage组件发送邮件,当邮件主题包含汉字并且长度较长时,会发生主题截断的现象,并且被截断的未解码的主题会放到邮件内容中
【原因】Indy的IdMessage组件在生成待发送的邮件时,主题中有汉字时会按RFC2045~2047的base64编码规范对主题进行编码,base64要求编码后每行长度不能超过75(76)个字节;所以当主题过长时要分行。问题是IdMessage编码时,用了2对分行符<CR><LF><CR><LF>,而RFC规定<CR><LF><CR><LF>表示邮件中一节的结束,所以接收邮件的程序只会对第1行解码,其余的理解为邮件内容了。
【解决办法】因为IdMessage没有提供直接修改编码后的邮件的方法,所以用IdMessage的SaveFromStream()和LoadFromStream()以及TStringList和TMemoryStream来去掉Email的Header部分多余的<CR><LF>。
感觉此方法笨了些,贴出来抛砖引语,看还有什么其他简单的办法。当然直接修改Indy的源代码最好,但俺不会delphi。真不方便,sigh~
//---------------------------------------------------------------------------
int __fastcall SMTP_SendMail(TIdSMTP* Smtp,TIdMessage *MsgSend,const TMailInfo& MI,String& sMsg)
{
//发送邮件
//注:发送的SMTP属性通过SMTP_Setup()函数设置了
//参数:
//in:
//Smtp:使用的IdSmtp控件
//MsgSend:使用的IdMessage控件
//MI:要发送的邮件信息
// OUT:
// Msg 返回错误信息
//返回值
//0: 成功发送
//-1:发送失败,参见Msg信息
//-2:连接失败,参见Msg信息
String s,sFile;
TStringList * slst = new TStringList;
//清除,否则包含有上一条的信息
MsgSend->Clear();
//是否要求收到回执
if (MI.bReturnReciept)
{//{We set the recipient to the From E-Mail address }
MsgSend->ReceiptRecipient->Text = MsgSend->From->Text;
}
else
{// {indicate that there is no receipt recipiant}
MsgSend->ReceiptRecipient->Text = "";
}
//发件人
MsgSend->From->Text = MI.sFrom;
//收件人
MsgSend->Recipients->EMailAddresses = MI.sTo; //{ To: header }
//邮件主题
MsgSend->Subject = MI.sSubject; //{ Subject: header }
//抄送
MsgSend->CCList->EMailAddresses = MI.sCc;// {CC}
//暗送
MsgSend->BccList->EMailAddresses = MI.sBcc; //{BCC}
//邮件优先级别
MsgSend->Priority = TIdMessagePriority(MI.tPriority);
//邮件内容类型
MsgSend->ContentType = MI.sContType;
MsgSend->Encoding = meUU;
//下面的一段代码解决这个bug
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////处理Header,去掉多余的CRLF
TMemoryStream* pms = new TMemoryStream();
MsgSend->SaveToStream(pms);
slst->Clear();
pms->Position = 0;
slst->LoadFromStream(pms);
for(int i=0;i<slst->Count;i++)
{
if(slst->Strings[i]=="")
{
slst->Delete(i);
}
}
slst->Add(""); //IdMessage的LoadFromStream()规定Stream必须以//<CR><LF><CR><LF>结尾
pms->Size = 0;
pms->Position = 0;
slst->SaveToStream(pms);
pms->Position = 0;
MsgSend->LoadFromStream(pms,true);
delete pms;
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//邮件内容
MsgSend->Body->Text = MI.sBody;
//附件
if(MI.sAttachList.Length() > 0)
{
slst->Clear();
slst->CommaText = MI.sAttachList;
for(int i=0;i<slst->Count;i++)
{
MsgSend->MessageParts->Add();
new TIdAttachment(MsgSend->MessageParts,slst->Strings[i]);//由第1句MsgSend->Clear()回收
}
}
delete slst;
sFile = s + "_2.eml";
// MsgSend->SaveToFile(sFile);
//连接SMTP服务器
if(!Smtp->Connected())
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
if(Smtp->ClosedGracefully)
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
//发送邮件
if(Smtp->Connected())
{
try
{
Smtp->Send(MsgSend);
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 发送邮件失败!";
sMsg += "From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,30);
sMsg += "......,";
sMsg += " [错误信息]:";
sMsg += s;
try
{
Smtp->CheckForGracefulDisconnect(true);
}
catch(...)
{
return -2;
}
try
{
Smtp->CheckForDisconnect(true,false);
}
catch(...)
{
return -2;
}
return -1;
}
}
else
{
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:连接断开!";
return -2;
}
// if(m_Para.bDebug)
{
sMsg = "成功发送邮件 From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,100);
sMsg += "......";
}
return 0;
}
【问题】用Indy9的IdSMTP和IdMessage组件发送邮件,当邮件主题包含汉字并且长度较长时,会发生主题截断的现象,并且被截断的未解码的主题会放到邮件内容中
【原因】Indy的IdMessage组件在生成待发送的邮件时,主题中有汉字时会按RFC2045~2047的base64编码规范对主题进行编码,base64要求编码后每行长度不能超过75(76)个字节;所以当主题过长时要分行。问题是IdMessage编码时,用了2对分行符<CR><LF><CR><LF>,而RFC规定<CR><LF><CR><LF>表示邮件中一节的结束,所以接收邮件的程序只会对第1行解码,其余的理解为邮件内容了。
【解决办法】因为IdMessage没有提供直接修改编码后的邮件的方法,所以用IdMessage的SaveFromStream()和LoadFromStream()以及TStringList和TMemoryStream来去掉Email的Header部分多余的<CR><LF>。
感觉此方法笨了些,贴出来抛砖引语,看还有什么其他简单的办法。当然直接修改Indy的源代码最好,但俺不会delphi。真不方便,sigh~
//---------------------------------------------------------------------------
int __fastcall SMTP_SendMail(TIdSMTP* Smtp,TIdMessage *MsgSend,const TMailInfo& MI,String& sMsg)
{
//发送邮件
//注:发送的SMTP属性通过SMTP_Setup()函数设置了
//参数:
//in:
//Smtp:使用的IdSmtp控件
//MsgSend:使用的IdMessage控件
//MI:要发送的邮件信息
// OUT:
// Msg 返回错误信息
//返回值
//0: 成功发送
//-1:发送失败,参见Msg信息
//-2:连接失败,参见Msg信息
String s,sFile;
TStringList * slst = new TStringList;
//清除,否则包含有上一条的信息
MsgSend->Clear();
//是否要求收到回执
if (MI.bReturnReciept)
{//{We set the recipient to the From E-Mail address }
MsgSend->ReceiptRecipient->Text = MsgSend->From->Text;
}
else
{// {indicate that there is no receipt recipiant}
MsgSend->ReceiptRecipient->Text = "";
}
//发件人
MsgSend->From->Text = MI.sFrom;
//收件人
MsgSend->Recipients->EMailAddresses = MI.sTo; //{ To: header }
//邮件主题
MsgSend->Subject = MI.sSubject; //{ Subject: header }
//抄送
MsgSend->CCList->EMailAddresses = MI.sCc;// {CC}
//暗送
MsgSend->BccList->EMailAddresses = MI.sBcc; //{BCC}
//邮件优先级别
MsgSend->Priority = TIdMessagePriority(MI.tPriority);
//邮件内容类型
MsgSend->ContentType = MI.sContType;
MsgSend->Encoding = meUU;
//下面的一段代码解决这个bug
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////处理Header,去掉多余的CRLF
TMemoryStream* pms = new TMemoryStream();
MsgSend->SaveToStream(pms);
slst->Clear();
pms->Position = 0;
slst->LoadFromStream(pms);
for(int i=0;i<slst->Count;i++)
{
if(slst->Strings[i]=="")
{
slst->Delete(i);
}
}
slst->Add(""); //IdMessage的LoadFromStream()规定Stream必须以//<CR><LF><CR><LF>结尾
pms->Size = 0;
pms->Position = 0;
slst->SaveToStream(pms);
pms->Position = 0;
MsgSend->LoadFromStream(pms,true);
delete pms;
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//邮件内容
MsgSend->Body->Text = MI.sBody;
//附件
if(MI.sAttachList.Length() > 0)
{
slst->Clear();
slst->CommaText = MI.sAttachList;
for(int i=0;i<slst->Count;i++)
{
MsgSend->MessageParts->Add();
new TIdAttachment(MsgSend->MessageParts,slst->Strings[i]);//由第1句MsgSend->Clear()回收
}
}
delete slst;
sFile = s + "_2.eml";
// MsgSend->SaveToFile(sFile);
//连接SMTP服务器
if(!Smtp->Connected())
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
if(Smtp->ClosedGracefully)
{
try
{
Smtp->Connect();
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:";
sMsg += s;
return -2;
}
}
//发送邮件
if(Smtp->Connected())
{
try
{
Smtp->Send(MsgSend);
}
catch(Exception &e)
{
s = AnsiReplaceStr(e.Message,"\r\n","");
sMsg = "Try Send: 发送邮件失败!";
sMsg += "From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,30);
sMsg += "......,";
sMsg += " [错误信息]:";
sMsg += s;
try
{
Smtp->CheckForGracefulDisconnect(true);
}
catch(...)
{
return -2;
}
try
{
Smtp->CheckForDisconnect(true,false);
}
catch(...)
{
return -2;
}
return -1;
}
}
else
{
sMsg = "Try Send: 连接SMTP服务器\'";
sMsg += Smtp->Host;
sMsg += "\'失败![错误信息]:连接断开!";
return -2;
}
// if(m_Para.bDebug)
{
sMsg = "成功发送邮件 From:";
sMsg += MI.sFrom;
sMsg += ",To:";
sMsg += MI.sTo;
sMsg += ",Suject=";
sMsg += MI.sSubject;
sMsg += ",Body=";
sMsg += MI.sBody.SubString(1,100);
sMsg += "......";
}
return 0;
}
#15
呵呵我用的是BCB.感觉还是用delphi好啊,可以直接改VCL,sigh
#16
我也在写收发邮件,如果有人愿意交流请加我的QQ:84560912或MSN:sunseave@hotmail.com
#17
我也遇见类似的问题了,不过不是发生邮件发送过程中,而是接受过程中。
从某些服务器接收的邮件标题无法还原为汉字,直接把base64编码格式显示出来了,如下:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
看来也是标题过长的原因?
现在仍然束手无策
从某些服务器接收的邮件标题无法还原为汉字,直接把base64编码格式显示出来了,如下:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
看来也是标题过长的原因?
现在仍然束手无策
#18
如果像楼上某位搂主所言,那倒不如直接空格替换中间的某段字符。
如:
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
用空格替换如下字符串,就可以了
?=
=?GB2312?B?
我试过的,替换后,有一个空格同样能正确解码。
如:
Subject:
=?GB2312?B?suLK1LLiytQxsuLK1LLiytQysuLK1LLiytQzsuLK1LLiytQ0suLK1LLiytQ1?=
=?GB2312?B?suLK1LLiytQ2?=
用空格替换如下字符串,就可以了
?=
=?GB2312?B?
我试过的,替换后,有一个空格同样能正确解码。