-
Notifications
You must be signed in to change notification settings - Fork 32
Message Templates
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.
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.
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
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.}.
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.
There are two strategies for using Templates in messages:
- Add
Templatesto theMailMergeMessageso they become a fixed part of them - Manage Templates apart from
MailMergeMessages
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);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);- You do not need
Partswith bothPartTypes,PartType.PlainandPartType.Html.PartType.Plaincan be used for plain and HTML messages. If noPartType.Htmlexists for a HTML message, thenPartType.Plainwill be inserted. - If the
Partsonly contain one or twoPartTypes with the sameKeyname, the firstPartwill be inserted if theDefaultKeyof theTemplateis null. - Trying to add a
Partwith an existingKeyname for thePartTypewill throw an exception.