无法使用TIdSMTP发送UTF-8消息

时间:2017-04-29 07:52:03

标签: delphi utf-8 indy indy10 delphi-10.1-berlin

我有按钮发送邮件:

procedure TRealization.Button17Click(Sender: TObject);
var
  EmailCore: TStringStream;
  EmailBody, sInvoices: string;
  FilePath: string;
  MailTitle: string;
  i: integer;
begin
  if (Languages.ItemIndex > -1) then begin
    EmailCore := TStringStream.Create('', TEncoding.UTF8);
    if Languages.ItemIndex = 0 then begin
        FilePath := ExtractFilePath(Application.ExeName)+'/languages/pl.html';
        MailTitle := 'Płatność dla '+Monitoring.l_client_name.Caption;
    end else if Languages.ItemIndex = 1 then begin
        FilePath := ExtractFilePath(Application.ExeName)+'/languages/en.html';
        MailTitle := 'Invoice payment for '+Monitoring.l_client_name.Caption;
    end;
    EmailCore.LoadFromFile(FilePath);
    for i := 0 to (preview_invoices.RowCount-1) do begin
      sInvoices := sInvoices+'<tr><td>'+preview_invoices.Cells[2,i]+'</td><td>'+preview_invoices.Cells[4,i]+'</td><td>'+preview_invoices.Cells[4,i]+'</td><td>'+preview_invoices.Cells[5,i]+'</td><td>'+preview_invoices.Cells[6,i]+'</td></tr>';
    end;
    EmailBody := StringReplace(EmailCore.DataString, ':LIST:', sInvoices, [rfReplaceAll]);
    EmailBody := StringReplace(EmailBody, ':COMPANY:', Monitoring.l_client_name.Caption, [rfReplaceAll]);
    EmailBody := StringReplace(EmailBody, ':VAT:', Monitoring.l_client_vat.Caption, [rfReplaceAll]);
    EmailBody := StringReplace(EmailBody, ':NAME:', Main.l_uname.Caption, [rfReplaceAll]);
    Main.SendEmailIndy('my.mail.com',
        Main.l_uname.Caption,
        _GlobalData.EMail,
        Emails.Text,
        _GlobalData.EMail,
        '',
        MailTitle,
        EMailBody,
        true,
        nil);
    EmailCore.Free;
  end;
end;

这是发送电子邮件的功能:

procedure TMain.SendEmailIndy(
        const SMTPServer: string;
        const FromName, FromAddress: string;
        const ToAddresses: string; //comma "," separated list of e-mail addresses
        const CCAddresses: string; //comma "," separated list of e-mail addresses
        const BCCAddresses: string; //comma "," separated list of e-mail addresses
        const Subject: string;
        const EmailBody: string;
        const IsBodyHtml: Boolean; //verses Plain Text
        const Attachments: TStrings);
var
    smtp: TIdSMTP; // IdSmtp.pas
    msg: TidMessage; // IdMessage.pas
    builder: TIdCustomMessageBuilder; //IdMessageBuilder.pas
    s: string;
    emailAddress: string;
begin
    msg := TidMessage.Create(nil);
    msg.Encoding := meMIME;
    msg.ContentType := 'text/html';
    msg.CharSet := 'UTF-8';
    msg.ContentTransferEncoding:= 'quoted-printable';
    try
        if IsBodyHtml then begin
            builder := TIdMessageBuilderHtml.Create;
            TIdMessageBuilderHtml(builder).Html.Text := EmailBody
        end else begin
            builder := TIdMessageBuilderPlain.Create;
        end;

        try
            if Attachments <> nil then
            begin
                for s in Attachments do
                    builder.Attachments.Add(s);
            end;

            builder.FillMessage(msg);
        finally
            builder.Free;
        end;

        msg.From.Name := FromName;
        msg.From.Address := FromAddress;
        msg.Subject := Subject;

        //If the message is plaintext then we must fill the body outside of the PlainText email builder.
        //(the PlainTextBuilder is unable to build plaintext e-mail)
        if not IsBodyHtml then begin
            msg.Body.Text := EmailBody;
        end;

        for s in ToAddresses.Split([',']) do
        begin
            emailAddress := Trim(s);
            if emailAddress <> '' then
            begin
                with msg.recipients.Add do
                begin
                    //Name := '<Name of recipient>';
                    Address := emailAddress;
                end;
            end;
        end;

        for s in CCAddresses.Split([',']) do
        begin
            emailAddress := Trim(s);
            if emailAddress <> '' then
                msg.CCList.Add.Address := emailAddress;
        end;

        for s in BCCAddresses.Split([',']) do
        begin
            emailAddress := Trim(s);
            if emailAddress <> '' then
                msg.BccList.Add.Address := emailAddress;
        end;

        smtp := TIdSMTP.Create(nil);
        try
            smtp.Host := SMTPServer; // IP Address of SMTP server
            Smtp.UseTLS := utNoTLSSupport;
            smtp.Port := 587; //The default already is port 25 (the SMTP port)
            smtp.Username := _GlobalData.EMail;
            smtp.Password := _GlobalData.Password;
            //Indy (and C# SmtpClient class) already defaults to the computer name
            //smtp.HeloName :=
            smtp.Connect;
        try
            smtp.Send(msg);
            ShowMessage('Wiadomość wysłana.');
            log('EMAIL', 'Wysłano zapytanie do '+ToAddresses, StrToInt(Monitoring.t_mid.Caption));
        finally
          //smtp.Disconnect();
        end;
    finally
        //smtp.Free;
    end;
finally
    //msg.Free;
end;
end;

问题是,当我收到一封电子邮件时,正文(电子邮件标题实际上很好并显示所有字符)包含问号,其中波兰语或德语字母是(±,ż,ó,ę,ö,ä等)。消息编码错误。我尝试使用UTF8Encode和其他解决方案,但没有任何实际工作。电子邮件不断发送内容已损坏。

我将不胜感激。

1 个答案:

答案 0 :(得分:4)

您的TIdMessage.CharSet作业被忽略,因为TIdMessageBuilder重置了CharSet(以及ContentTypeContentTransferEncodingEncoding属性)填充TIdMessage

因此,您需要设置TIdMessageBuilderPlain.PlainTextCharSetTIdMessageBuilderHtml.HtmlCharSet属性。

此外,您不需要单独使用TIdMessageBuilderPlainTIdMessageBuilderHtml。您可以单独使用TIdMessageBuilderHtml,因为它可以创建纯文本和HTML电子邮件,具体取决于填充的属性。您的评论&#34; 如果邮件是纯文本,那么我们必须填写PlainText电子邮件构建器之外的正文。 PlainTextBuilder无法构建明文电子邮件&#34;完全不真实,如my blog article on how to use TIdMessageBuilderHtml中所述。

试试这个功能代码:

procedure TMain.SendEmailIndy(
  const SMTPServer: string;
  const FromName, FromAddress: string;
  const ToAddresses: string; //comma "," separated list of e-mail addresses
  const CCAddresses: string; //comma "," separated list of e-mail addresses
  const BCCAddresses: string; //comma "," separated list of e-mail addresses
  const Subject: string;
  const EmailBody: string;
  const IsBodyHtml: Boolean; //verses Plain Text
  const Attachments: TStrings);
var
  smtp: TIdSMTP; // IdSmtp.pas
  msg: TidMessage; // IdMessage.pas
  builder: TIdMessageBuilderHtml; //IdMessageBuilder.pas
  s: string;
  emailAddress: string;
begin
  msg := TIdMessage.Create(nil);
  try
    builder := TIdMessageBuilderHtml.Create;
    try
      if IsBodyHtml then
      begin
        builder.Html.Text := EmailBody;
        builder.HtmlCharSet := 'utf-8';
      end else
      begin
        builder.PlainText.Text := EmailBody;
        builder.PlainTextCharSet := 'utf-8';
      end;

      if Attachments <> nil then
      begin
        for s in Attachments do
          builder.Attachments.Add(s);
      end;

      builder.FillMessage(msg);
    finally
      builder.Free;
    end;

    msg.From.Name := FromName;
    msg.From.Address := FromAddress;
    msg.Subject := Subject;

    msg.Recipients.EmailAddresses := ToAddresses;
    msg.CCList.EmailAddresses := CCAddresses;
    msg.BccList.EmailAddresses := BCCAddresses;

    smtp := TIdSMTP.Create(nil);
    try
      smtp.Host := SMTPServer; // IP Address of SMTP server
      smtp.UseTLS := utNoTLSSupport;
      smtp.Port := 587; //The default already is port 25 (the SMTP port)
      smtp.Username := _GlobalData.EMail;
      smtp.Password := _GlobalData.Password;
      //Indy (and C# SmtpClient class) already defaults to the computer name
      //smtp.HeloName :=
      smtp.Connect;
      try
        smtp.Send(msg);
        log('EMAIL', 'Wysłano zapytanie do '+ToAddresses, StrToInt(Monitoring.t_mid.Caption));
      finally
        smtp.Disconnect;
      end;
      ShowMessage('Wiadomość wysłana.');
    finally
      smtp.Free;
    end;
  finally
    msg.Free;
  end;
end;

另外,仅供参考,如果您使用UseTLS=utNoTLSSupport,那么您应该使用Port=25。如果您想使用Port=587,那么您应该使用UseTLS=utUseExplicitTLS代替{需要SSLIOHandler分配给TIdSMTP.IOHandler属性,例如TIdSSLIOHandlerSocketOpenSSL。 / p>