Viktor Anastasov
Viktor Anastasov

Reputation: 1113

Indy send email with receivers having UTF-8 characters

I'm trying to send an email with the TIdSMTP component in Indy 10 and the list of my receivers has Unicode characters in it (like Роман Безяк <[email protected]>). But when the mail is sent, in the To header of the email I see this: "?????????" <[email protected]>. Can anyone help me fix this encoding problem?

This is how my procedure looks like :

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 'Роман Безяк <[email protected]>'
        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;

Upvotes: 4

Views: 1350

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595827

Recipients.Add.Address := myReceiver; // cyrillic symbols! like 'Роман Безяк <[email protected]>'

If myReceiver contains both name and email address, you need to use the TIdEMailAddressItem.Text property instead of the TIdEMailAddressItem.Address property:

Recipients.Add.Text := myReceiver; // cyrillic symbols! like 'Роман Безяк <[email protected]>'
// Name becomes 'Роман Безяк'
// Address becomes '[email protected]'...

The TIdEmailAddressItem.Text property setter method parses the input string and splits it into the TIdEmailAddressItem.Name and TIdEmailAddressItem.Address properties accordingly.

The TIdEmailAddressItem.Address property has no setter method at all, so whatever you assign is used as-is.

When encoding an email, the TIdEmailAddressItem.Name value gets MIME-encoded per RFC 2047 if any non-ASCII characters are present. The TIdEmailAddressItem.Address value does not get MIME-encoded, due to an assumption that email addresses only ever contain ASCII characters (Unicode email addresses do exist but are not commonly used yet). Email headers must be in ASCII, so you are seeing Роман Безяк become ????????? because you stuck it in the TIdEmailAddressItem.Address property and it got converted as-is to ASCII (where non-ASCII characters become ?) without being MIME-encoded.

So, by separating the Name from the Address, you should see Роман Безяк being handled correctly.

Upvotes: 4

Related Questions