New HTML Message Builder class

Update Dec 5 2016: this article has been updated to include changes made to the IdMessageBuilder unit since this article was first written in 2008.

Many people ask how to create HTML messages in Indy. Due to the nature of MIME nesting, and how Indy 10 implements pseudo-nesting support via the TIdMessagePart.ParentPart property, this is not always easy to do correctly. In my earlier article about HTML Messages, I explained in detail how to correctly set up the pieces of the TIdMessage component for creating mixed text/html/attachment emails in different scenerios. To make this task even easier, I have used that information to create a new set of helper classes to handle the ugly details for you! Now, all you have to do is set a few properties and the contents of a TIdMessage will be filled in appropriately.

Introducing the IdMessageBuilder unit

A new unit named IdMessageBuilder.pas has been added to the IndyProtocols package. This unit declares a base class TIdCustomMessageBuilder and 2 descendants – TIdMessageBuilderHtml and TIdMessageBuilderRtf (I will not cover TIdMessageBuilderRtf in this article). These classes are light-weight helpers. They are designed with the most common usage scenerios in mind. For more specialized layouts, you have to continue setting up the TIdMessage.MesageParts collection manually.

The TIdCustomMessageBuilder class declares 4 public properties:

  • Attachments: a TStrings to contain local file names that are to be attached to the message, and do not relate to any other sections of the message. The email receiver can save these attachments to files as desired.
  • PlainText: a TStrings to contain the email’s plain textual data. This is the content that will be displayed to MIME-enabled readers which do no support more specialized content generated by a derived class.
  • PlainTextCharset: the character set that the PlainText will be encoded in (UTF-8, etc). If not specified, Indy’s default charset will be used.
  • PlainTextContentTransfer: the transfer encoding that the charset-encoded PlainText will be encoded in (base64, quoted-printable, etc). If not specified, ‘quoted-printable’ will be used.

And two public methods:

  • FillMessage: fills in the content data for an existing TIdMessage object instance.
  • NewMessage: instantiates a new TIdMessage object instance and fills it via FillMessage().

The TIdMessageBuilderHtml class derived from TIdCustomMessageBuilder to add 5 more public properties:

  • Html: a TStrings to contain the email’s HTML textual data. This is the content that will be displayed to MIME-enabled readers which support HTML.
  • HtmlCharset: the character set that the HTML will be encoded in (UTF-8, etc). If not specified, Indy’s default charset will be used. If the HTML contains a <meta> tag to specify its own charset, it should match the charset used by TIdMessageBuilderHtml to avoid rendering issues for the reader.
  • HtmlContentTransfer: the transfer encoding that the charset-encoded HTML will be encoced in (base64, quoted-printable, etc). If not specified, ‘quoted-printable’ will be used.
  • HtmlFiles: a TStrings to contain local file names that are to be attached to the message. These files are to be referenced by the HTML, such as embedded images and other multimedia files.
  • HtmlViewerNeededMsg: a plain text message to be displayed to non-HTML readers, if none is specified in the PlainText property.

Although TIdCustomMessageBuilder and its descendants do the bulk of the work for you in setting up TIdMessage’s body, you are responsible for setting up TIdMessage’s various header values OTHER THAN the ContentType property. This property are managed for you, based on the generated body content. By leaving the rest of the headers alone, you can include custom headers, specify recipients, etc as desired before saving/transmitting the message.

Using TIdMessageBuilderHtml

Rather than jump into the details about how the TIdMessageBuilderHtml class works internally, I’m going to just show code snippets of it in action. I will demonstrate the same message scenerios that are listed in my earlier article. Remember to add the IdMessageBuilder unit to your uses clause:

Plain-text and no HTML and no attachments

with TIdMessageBuilderHtml.Create do
try
  PlainText.Text := 'plain text goes here';
  FillMessage(IdMessage1);
finally
  Free;
end;

HTML and no plain text and no attachments

with TIdMessageBuilderHtml.Create do
try
  Html.Text := 'HTML goes here';
  FillMessage(IdMessage1);
finally
  Free;
end;

Plain-text and HTML and no attachments

with TIdMessageBuilderHtml.Create do
try
  PlainText.Text := 'plain text goes here';
  Html.Text := 'HTML goes here';
  FillMessage(IdMessage1);
finally
  Free;
end;

HTML and non-related attachments and no plain-text

with TIdMessageBuilderHtml.Create do
try
  Html.Text := 'HTML goes here';
  Attachments.Add('c:\folder\archive.zip');
  FillMessage(IdMessage1);
finally
  Free;
end;

HTML and related attachments and no plain-text

with TIdMessageBuilderHtml.Create do
try
  Html.Text := 'HTML goes here';
  HtmlFiles.Add('c:\folder\image1.jpg');
  HtmlFiles.Add('c:\folder\image2.jpg');
  FillMessage(IdMessage1);
finally
  Free;
end;

Plain-text and HTML and attachments

HTML-related attachments only

with TIdMessageBuilderHtml.Create do
try
  PlainText.Text := 'plain text goes here';
  Html.Text := 'HTML goes here';
  HtmlFiles.Add('c:\folder\image1.jpg');
  HtmlFiles.Add('c:\folder\image2.jpg');
  FillMessage(IdMessage1);
finally
  Free;
end;

Non-related attachments only

with TIdMessageBuilderHtml.Create do
try
  PlainText.Text := 'plain text goes here';
  Html.Text := 'HTML goes here';
  Attachments.Add('c:\folder\archive.zip');
  FillMessage(IdMessage1);
finally
  Free;
end;

Related and non-related attachments

with TIdMessageBuilderHtml.Create do
try
  PlainText.Text := 'plain text goes here';
  Html.Text := 'HTML goes here';
  HtmlFiles.Add('c:\folder\image1.jpg');
  HtmlFiles.Add('c:\folder\image2.jpg');
  Attachments.Add('c:\folder\archive.zip');
  FillMessage(IdMessage1);
finally
  Free;
end;

Note: the HtmlFiles property supports user defined ContentID values for each related attachment. By default, an attachment’s filename is used as its ContentID, where your HTML would refer to that value like so: <img src=”cid:image1.jpg”>. If the HTML wants to use custom ID values, the HtmlFiles.Add() method has an optional AContentID parameter, and the TIdMessageBuilderAttachment class has a public ContentID property, for that purpose.