Skip to content

Message Templates

Norbert Bietsch edited this page Mar 7, 2018 · 1 revision

The plain or HTML text of a mail message with its {placeholders} actually already can be called a template on the top level.

Templates in the sense of MailMergeLib offer to include any parts of text which shall be used or not depending on certain conditions. In the code you only have to define the condition for certain text parts. You do not have to include the text itsself. This way, the text may change without code modification.

The number of templates inside a mail message is unlimited.

Understanding Templates

A sample will make this more clear: Assume you want to choose the personalized salutation in a mail message depending on how close the relation to the recipient is.

Include Logic and Text in Code

You could code like this - not the recommended way:

var variables = new Dictionary<string, string> 
	{ { "firstName", "John" }, { "lastName", "Specimen" }, { "gender", "m" } };
var salutationType = Logic.GetSalutationType(...); // e.g. "friend"
switch (salutationType)
{
    case "friend":
        variables.Add("salutation", $"Hi {variables["firstName"]}");
        break;
    case "well-known":
        variables.Add("salutation", $"Dear {(variables["gender"] == "m" ? "Mr." : "Mrs.")} {variables["lastName"]}");
        break;
    case "formal":
    default:
        variables.Add("salutation", "Dear Sir or Madam");
        break;
}
var mmm = new MailMergeMessage("The Subject", "some text {salutation} more text");
// add addresses and other stuff here
new MailMergeSender().Send(mmm, (object) variables);

This has several disadvantages:

  • The resulting salutation value is a combination of values from other variables
  • Adding text formatting e.g. for the lastName is not possible, or you would have add this also to the code
  • The code contains literal text, which is not part of the mail message definition
  • Adding another salutationType requires changes in code and thus a recompiled assembly
  • Making a distinction between plain and HTML text would require additional program logic

Templates: Define More, Code Less

The Message Text Including a Template

Let's prepare an xml file with the following content, which will be de-serialized later.

<MailMergeMessage>
  <PlainText><![CDATA[some text {:template(Salutation)} more text]]></PlainText>
  <HtmlText><![CDATA[<html><head></head><body>some text {:template(Salutation)} more text</body></html>]]></HtmlText>
  <Templates>
    <Template Name="Salutation">
      <Text DefaultKey="formal">
        <Part Key="friend" Type="Plain"><![CDATA[Hi {firstName}\n]]></Part>
        <Part Key="friend" Type="Html"><![CDATA[Hi <b>{firstName}</b><br/>]]></Part>
        <Part Key="well-known" Type="Plain"><![CDATA[Dear {gender:choose(m):Mr|Mrs} {lastName}\n]]></Part>
        <Part Key="well-known" Type="Html"><![CDATA[Dear {gender:choose(m):Mr|Mrs} <b>{lastName}</b><br/>]]></Part>
        <Part Key="formal" Type="Plain"><![CDATA[Dear Sir or Madam\n]]></Part>
        <Part Key="formal" Type="Html"><![CDATA[<b>Dear Sir or Madam</b><br/>]]></Part>
      </Text>
    </Template>
  </Templates>
</MailMergeMessage>

Note This sample applies the built-in Choose Formatter Extension: {gender:choose(m):Mr.|Mrs.}.

Add Some Code

var variables = new Dictionary<string, string> 
	{ { "firstName", "John" }, { "lastName", "Specimen" }, { "gender", "m" } };
var mmm = MailMergeMessage.Deserialize(@"path-to-xml-file", Encoding.UTF8);
mmm.Templates["Salutation"].Key = Logic.GetSalutationType(...); // e.g. "friend"
// add addresses and other stuff here
new MailMergeSender().Send(mmm, (object) variables);

This is much better:

  • The template gets all variables to build the desired result without additionally coded data
  • Get the plain and HTML text parts in a simple and transparent way
  • Format plain and HTML text parts independently with no code
  • For a new SalutationType just add another part to the "Salutation" Template with no code
  • Need the message for another language? Edit the xml file and you're done.

Using Templates

There are two strategies for using Templates in messages:

  • Add Templates to the MailMergeMessage so they become a fixed part of them
  • Manage Templates apart from MailMergeMessages

Temples as Part of the MailMergeMessage

This way the Templates become a fixed part of the MailMergeMessage. You can serialize the message to the file system and Templates will be included.

var mmm = new MailMergeMessage();
// some more stuff
mmm.Templates.Clear();
mmm.Templates.Add(new Template("Salutation",
    new Parts
    {
        new Part(PartType.Plain, "Hi", "Hi {FirstName}"),
        new Part(PartType.Html, "Hi", "Hi <b>{FirstName}</b><br>"),
        new Part(PartType.Plain, "Dear", "Dear {FirstName}"),
        new Part(PartType.Html, "Dear", "Dear <b>{FirstName}</b><br>"),
        new Part(PartType.Plain, "Formal", "Dear Sir or Madam"),
        new Part(PartType.Html, "Formal", "<b>Dear Sir or Madam</b><br>"),
    }, "Formal"));
mmm.Serialize("path-to-message", Encoding.UTF8);

Attach the same Templates to serveral MailMergeMessages

You can attach the Templates to different MailMergeMessage. For this it will be useful to save the Templates to a file, and Add the Templates to new messages as needed.

var templates = new Templates
{
    new Template("Salutation",
        new Parts
        {
            new Part(PartType.Plain, "Hi", "Hi {FirstName}"),
            new Part(PartType.Html, "Hi", "Hi <b>{FirstName}</b><br>"),
            new Part(PartType.Plain, "Dear", "Dear {FirstName}"),
            new Part(PartType.Html, "Dear", "Dear <b>{FirstName}</b><br>"),
            new Part(PartType.Plain, "Formal", "Dear Sir or Madam"),
            new Part(PartType.Html, "Formal", "<b>Dear Sir or Madam</b><br>"),
        }, "Formal")
};
templates.Serialize("path-to-template-file", Encoding.UTF8);
var mmm1 = new MailMergeMessage();
mmm1.Templates.AddRange(Templates.Deserialize("path-to-template-file", Encoding.UTF8));
//later: save the message without the templates
mmm1.Templates.Clear();
mmm1.Serialize("path-to-message-1", Encoding.UTF8);
var mmm2 = new MailMergeMessage();
mmm2.Templates.AddRange(Templates.Deserialize("path-to-template-file", Encoding.UTF8));
//later
mmm2.Templates.Clear();
mmm2.Serialize("path-to-message-2", Encoding.UTF8);

Logic Implemented in Templates

  • You do not need Parts with both PartTypes, PartType.Plain and PartType.Html. PartType.Plain can be used for plain and HTML messages. If no PartType.Html exists for a HTML message, then PartType.Plain will be inserted.
  • If the Parts only contain one or two PartTypes with the same Key name, the first Part will be inserted if the DefaultKey of the Template is null.
  • Trying to add a Part with an existing Key name for the PartType will throw an exception.