Indy 使用具有 UTF-8 字符的收件人发送电子邮件

Indy send email with receivers having UTF-8 characters

我正在尝试在 Indy 10 中发送带有 TIdSMTP 组件的电子邮件,我的收件人列表中包含 Unicode 字符(如 Роман Безяк <roman_bezjak@yahoo.com>)。但是在发送邮件时,在电子邮件的 To header 中我看到了:"?????????" <roman_bezjak@yahoo.com>。谁能帮我解决这个编码问题?

我的程序是这样的:

procedure TMailClientForm.btnSendEmailClick(Sender: TObject);
var
  mes : TIdMessage;
  i : Integer;
begin
  with SMTPClient do begin
    Host := serverHost;
    Port := SmtpServerPort;
    Username := myUserName;
    Password := myPassword;
    UseTLS := utUseImplicitTLS;
  end;
  try 
    mes := tidmessage.Create(nil);
    try
      with mes do begin
        ContentType := 'text/plain';
        ClearBody;
        Body.Text := memoEmailBody.Text;
        Subject := txtEmailSubject.text;
        From.Address := SMTPClient.Username; 
        From.Name := myName; // cyrillic symbols!
        Recipients.Add.Address := myReceiver; // cyrillic symbols! like 'Роман Безяк <roman_bezjak@yahoo.com>'
        CharSet := 'utf-8';
      end;
      if fileNames.Count > 0 then // attachments - the files are in the stringlist fileNames
        mes.ContentType := 'multipart/mixed';
      for i := 0 to fileNames.count - 1 do begin
        if FileExists(fileNames[i]) then
          TIdAttachmentFile.Create(mes.MessageParts, fileNames[i]);
      end;
      try
        try
          try
            SMTPClient.Connect;
          except
            on e : Exception do begin
              MessageDlg('ERROR=' + SMTPClient.LastCmdResult.Text.Text, mtError,   [mbOK], 0);
              Exit;
            end;
          end;
          try
            SMTPClient.Send(mes);            
          except
            on e : Exception do begin
              MessageDlg('ERROR=' + SMTPClient.LastCmdResult.Text.Text, mtError, [mbOK], 0);
              Exit;
            end;
          end;
        finally
          if SMTPClient.Connected then
            SMTPClient.Disconnect;
        end;
        fileNames.clear;
      except
        on e:exception do begin
          MessageDlg(e.message, mtError, [mbOK], 0);
        end;
      end;
    finally
      mes.Free;
    end;
  except
    on e:exception do begin
      MessageDlg(e.message, mtError, [mbOK], 0);
    end;
  end;
end;
Recipients.Add.Address := myReceiver; // cyrillic symbols! like 'Роман Безяк <roman_bezjak@yahoo.com>'

如果 myReceiver 包含姓名和电子邮件地址,您需要使用 TIdEMailAddressItem.Text 属性 而不是 TIdEMailAddressItem.Address 属性:

Recipients.Add.Text := myReceiver; // cyrillic symbols! like 'Роман Безяк <roman_bezjak@yahoo.com>'
// Name becomes 'Роман Безяк'
// Address becomes 'roman_bezjak@yahoo.com'...

TIdEmailAddressItem.Text 属性 setter 方法解析输入字符串并相应地将其拆分为 TIdEmailAddressItem.NameTIdEmailAddressItem.Address 属性。

TIdEmailAddressItem.Address 属性 根本没有 setter 方法,所以无论你分配什么,都会使用 as-is.

编码电子邮件时,如果存在任何 non-ASCII 个字符,TIdEmailAddressItem.Name 值会根据 RFC 2047 得到 MIME-encoded。 TIdEmailAddressItem.Address 值不会得到 MIME-encoded,因为假设电子邮件地址只包含 ASCII 字符(Unicode 电子邮件地址确实存在,但还不常用)。电子邮件 headers 必须是 ASCII,所以你看到 Роман Безяк 变成了 ????????? 因为你把它放在了 TIdEmailAddressItem.Address 属性 并且它被转换了 as-is 到 ASCII(其中 non-ASCII 个字符变为 ?)而不是 MIME-encoded.

因此,通过将 NameAddress 分开,您应该会看到 Роман Безяк 得到了正确处理。