I have button to send a mail:
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;
And this is a function for sending e-mails:
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;
The problem is that when I receive an email, the body (e-mail title is actually fine and displays all characters) contains question marks where Polish or German letters are (ą, ż, ó, ę, ö, ä etc.). The message is badly encoded. I tried using UTF8Encode and other solutions found here but nothing actually worked. E-mails keep being sent with corrupted content.
I would appreciate any help.
Your assignment of TIdMessage.CharSet
is ignored because TIdMessageBuilder
resets the CharSet
(and the ContentType
, ContentTransferEncoding
, and Encoding
properties) before populating the TIdMessage
.
As such, you need to set the TIdMessageBuilderPlain.PlainTextCharSet
and TIdMessageBuilderHtml.HtmlCharSet
properties instead.
Also, you don't need to use TIdMessageBuilderPlain
and TIdMessageBuilderHtml
separately. You can use TIdMessageBuilderHtml
by itself, as it can create both plain-text and HTML emails, depending on which properties are filled. Your comment that "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" is completely untrue, as explained in my blog article on how to use TIdMessageBuilderHtml
.
Try this function code:
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;
Also, just FYI, if you use UseTLS=utNoTLSSupport
then you should be using Port=25
. If you want to use Port=587
then you should be using UseTLS=utUseExplicitTLS
instead (which requires an SSLIOHandler
be assigned to the TIdSMTP.IOHandler
property, like TIdSSLIOHandlerSocketOpenSSL
).