Indy总有大大小小的Bug,但是有时候你又离不开它,真是进退两难的感觉。最新的Indy10同样有不少的BUG,最近在做邮件接收的一个模块,碰到了令人头痛的乱码问题,一阵研究之后,得出如下心得:
在接收邮件的时候,一般是这样的代码:
for i := 1 to MailCount do
begin
IdMessage1.Clear;
FContent := '';
IdMessage1.ContentType := 'Multipart/*';
IdMessage1.CharSet := 'GB2312';
FPOP3.Retrieve(i, IdMessage1);
FFrom := (IdMessage1.From.Text);
FSubject := IdMessage1.Subject;
FFrom := CheckTxt(FFrom);
FSubject := CheckTxt(FSubject);
Fcontent := IdMessage1.Body.Text;
for j := 0 to pred(IdMessage1.MessageParts.Count) do
begin
if IdMessage1.MessageParts.Items[j] is TIdText then
begin //正文
FContent := FContent + TIdText(IdMessage1.MessageParts.Items[j]).Body.Text;
end;
end;
end;
Fcontent := IdMessage1.Body.Text; 这一句保证邮件是SinglePart的时候同样显示内容,但是可能存在乱码,解决方法在下面。
首先解决邮件是MultiPart的时候,邮件体乱码的解决方法(方法来源于网上,参见:http://blog.csdn.net/kevinsh/article/details/6163029)
在IdMessageClient单元的ProcessTextPart函数中增加这一段(try和RemoveLastBlankLine(LTxt.Body)之间)
try
//ReadStringsAsContentType(LMStream, LTxt.Body, LHdrs.Values[SContentType], QuoteMIME);
{$IFDEF STRING_IS_ANSI}
cp := GetOEMCP;
LDestEncoding := TIdTextEncoding.GetEncoding(cp);
ReadStringsAsContentType(LMStream, LTxt.Body, LHdrs.Values[SContentType], QuoteMIME, LDestEncoding);
{$ELSE}
ReadStringsAsContentType(LMStream, LTxt.Body, LHdrs.Values[SContentType], QuoteMIME);
{$ENDIF}
RemoveLastBlankLine(LTxt.Body);
改完后,发现GB2312编码的邮件标题和邮件体都存在乱码现象,解决方法如下:
IdGlobalProtocols.pas单元ReadStringsAsCharset改成下面:
procedure ReadStringsAsCharset(AStream: TStream; AStrings: TStrings; const ACharset: String
{$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
);
var
LEncoding: TIdTextEncoding;
cp:Word;
begin
//LEncoding := CharsetToEncoding(ACharset);
{$IFDEF DOTNET_OR_ICONV}
LEncoding := TIdTextEncoding.GetEncoding(ACharSet);
{$ELSE}
CP := CharsetToCodePage(ACharSet);
Assert(CP <> 0);
LEncoding := TIdTextEncoding.GetEncoding(CP);
{$ENDIF}
{$IFNDEF DOTNET}
try
{$ENDIF}
{$IFDEF HAS_TEncoding}
AStrings.LoadFromStream(AStream, LEncoding);
{$ELSE}
//AStrings.Text := ReadStringFromStream(AStream, -1, LEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
AStrings.Text := ReadStringFromStream(AStream, -1, ADestEncoding);
{$ENDIF}
{$IFNDEF DOTNET}
finally
LEncoding.Free;
end;
{$ENDIF}
end;
IdHeaderCoderPlain.pas单元的类方法TIdHeaderCoderPlain.Decode改成这样:
class function TIdHeaderCoderPlain.Decode(const ACharSet: string; const AData: TIdBytes): String;
var
LEncoding: TIdTextEncoding;
LBytes: TIdBytes;
{$IFNDEF DOTNET_OR_ICONV}
CP: Word;
{$ENDIF}
begin
{if ACharSet <> 'GB2312' then
Result := BytesToString(AData, Indy8BitEncoding);
else }
begin
Result := '';
LBytes := nil;
try
{$IFDEF DOTNET_OR_ICONV}
LEncoding := TIdTextEncoding.GetEncoding(ACharSet);
{$ELSE}
CP := CharsetToCodePage(ACharSet);
Assert(CP <> 0);
LEncoding := TIdTextEncoding.GetEncoding(CP);
{$ENDIF}
{$IFNDEF DOTNET}
try
{$ENDIF}
LBytes := AData;
if LEncoding <> TIdTextEncoding.Unicode then begin
LBytes := TIdTextEncoding.Convert(LEncoding, TIdTextEncoding.Unicode, LBytes);
end;
Result := TIdTextEncoding.Unicode.GetString(LBytes, 0, Length(LBytes));
{$IFNDEF DOTNET}
finally
LEncoding.Free;
end;
{$ENDIF}
except
end;
end;
end;
重新编译Indy(废话),OK,这样应该能解决绝大多数的邮件乱码问题了。如果您发现了还有什么更好的方法,希望一起交流