1

我正在使用 Indy 从 Android 设备发送一个 .txt 文件作为附件。

当我下载此文件时,.txt 文件的编码已从 UTF-8 更改为 ANSI,并在彼此相邻的行中显示其内容,而不是在彼此下方。

那么我做错了什么,如何解决这个问题?

用于发送邮件的功能代码:

Body := TStringList.Create;
IdSMTP := TIdSMTP.Create(nil);
SSLHandler:= TIdSSLIOHandlerSocketOpenSSL.Create(Form1);
IdSMTP.IOHandler:= SSLHandler;
IdSMTP.UseTLS:= utUseExplicitTLS;

IdSMTP.Host := 'smtp.gmail.com';
IdSMTP.Port := 587;
IdSMTP.AuthType := satDefault;
IdSMTP.Username := AppData.MailAddrSender;
IdSMTP.Password := Appdata.MailPassword;

IdMessage := TIdMessage.Create(nil);
IdMessage.From.Name := aName;
IdMessage.From.Address := AppData.MailAddrSender;
IdMessage.Subject := 'E-mail subject';

PathString := System.IOUtils.TPath.Combine(System.IOUtils.TPath.GetDocumentsPath, (PathString + 'Log.txt'));
Body.Add('Mail todays log,');
if FileExists(PathString) then
  TIdAttachmentFile.Create(IdMessage.MessageParts,PathString);
try
  for I := 0 to Body.Count -1 do
    IdMessage.Body.Add(Body.Strings[I]);
  IdEmailAddressItem := IdMessage.Recipients.Add;
  IdEmailAddressItem.Address := AppData.MailAddrReceiver;

  try
    IdSMTP.Connect;
    try
      if IdSMTP.Authenticate then
      IdSMTP.Send(IdMessage);

    finally
      IdMessage.Free;
      IdSMTP.Disconnect;
    end;

  except
    on E: Exception do
    //exception handling here
  end;
finally
  IdSMTP.Free;
  SSLHandler.DisposeOf;
  Body.DisposeOf;
end;

感谢您的时间。

4

1 回答 1

1

当我下载这个时,.txt 文件的编码已从 UTF-8 更改为 ANSI

使用时TIdAttachmentFile,文件的原始字节按原样发送。Indy 不会更改附加文件的编码。

TIdAttachmentFileContentType根据您传递给构造函数的文件名的扩展名默认其属性值。在这种情况下,扩展名.txt应该ContentType默认为text/plain. text/...媒体类型有一个与之关联的charset属性,但您没有Charset在代码中设置附件的属性。否则,接收者将使用默认值charset来解释数据(通常us-ascii根据 RFC 822)。因此,接收者很可能正在检测text/plain缺少的媒体类型并charset以ASCII/ANSI显示文件数据,因为它不知道数据实际上是 UTF-8 编码的(因为文件是附件,所以接收者应该正在储蓄如果将附件保存到新文件,则原始字节原样)。

如果您知道要附加的文件是以 UTF-8 编码的事实,则应该明确说明:

if FileExists(PathString) then
begin
  Attachment := TIdAttachmentFile.Create(IdMessage.MessageParts, PathString);
  Attachment.ContentType := 'text/plain';
  Attachment.Charset := 'utf-8';
end;

并在彼此相邻的行中显示其内容,而不是在彼此下方。

这听起来更像是换行问题而不是编码问题。例如,如果 Android 上的原始文件使用LF换行符,但收件人只支持CRLF换行符。

如果需要,可以让 Indy 将换行符标准化为CRLF. 您只需将文件数据加载到 aTIdText而不是 aTIdAttachmentFile中,然后确保将TIdText.ContentDisposition属性设置为attachment(否则它将默认为inline),并设置TIdText.FileName,因此数据仍被收件人视为附件:

if FileExists(PathString) then
begin
  Attachment := TIdText.Create(IdMessage.MessageParts, nil);
  Attachment.Body.LoadFromFile(PathString, TEncoding.UTF8);
  Attachment.ContentType := 'text/plain';
  Attachment.Charset := 'utf-8';
  Attachment.ContentDisposition := 'attachment';
  Attachment.FileName := ExtractFileName(PathString);
end;

现在,综上所述,您在使用 Indy 组件时通常会遇到一些其他小的编码问题。我会建议更像这样的东西:

try
  IdSMTP := TIdSMTP.Create(nil);
  try
    SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdSMTP);
    IdSMTP.IOHandler := SSLHandler;
    IdSMTP.UseTLS := utUseExplicitTLS;

    IdSMTP.Host := 'smtp.gmail.com';
    IdSMTP.Port := 587;
    IdSMTP.AuthType := satDefault;
    IdSMTP.Username := AppData.MailAddrSender;
    IdSMTP.Password := Appdata.MailPassword;

    IdMessage := TIdMessage.Create(nil);
    try
      IdMessage.From.Name := aName;
      IdMessage.From.Address := AppData.MailAddrSender;
      IdMessage.Subject := 'E-mail subject';

      IdEmailAddressItem := IdMessage.Recipients.Add;
      IdEmailAddressItem.Address := AppData.MailAddrReceiver;

      IdMessage.Body.Add('Mail todays log,');

      PathString := System.IOUtils.TPath.Combine(System.IOUtils.TPath.GetDocumentsPath, PathString + 'Log.txt');
      if FileExists(PathString) then
      begin
        // or TIdText...
        Attachment := TIdAttachmentFile.Create(IdMessage.MessageParts, PathString);
        Attachment.ContentType := 'text/plain';
        Attachment.Charset := 'utf-8';
      end;

      IdSMTP.Connect;
      try
        IdSMTP.Send(IdMessage);
      finally
        IdSMTP.Disconnect;
      end;
    finally
      IdMessage.Free;
    end;
  finally
    IdSMTP.Free;
  end;
except
  on E: Exception do
    //exception handling here
end;
于 2015-06-11T17:20:12.697 回答