-
Notifications
You must be signed in to change notification settings - Fork 32
Message Composition
In order to create a new message where {placeholders}
shall be used, we need a data source. For this example it will be the following array:
Note: In all properties of a
MailMergeMessage
{placeholders}
can be inserted, e.g. the subject, mailbox addresses, plain and HTML text, attachments, headers, ...
var variables = new[]
{
new
{
FirstName = "John",
LastName = "Specimen",
Email = "[email protected]",
Image = "john.jpg",
Attachment = "EventJohn.pdf"
},
new
{
FirstName = "Mary",
LastName = "Specimen",
Email = "[email protected]",
Image = "mary.jpg",
Attachment = "EventMary.pdf"
}
};
Next we create an instance of a MailMergeMessage
. We want a personalized subject and we also add a MessageInfo
with some background information about the message. The MessageInfo
is optional but recommended.
var mmm = new MailMergeMessage("Event offer for you, {FirstName}")
{
Info = new MessageInfo()
{
Id = 1,
Category = "Customers",
Description = "Event offer",
Comments = "with personalized PDF attachment",
Data = ""
}
};
As you see, the MessageInfo
also has property Data
. For this example we will leave it blank.
MessageInfo.Data
allows for storing "data hints". This could be e.g.
- SQL statement for retrieving data from a database
- A list of recipients
- Other information for your data specific program logic
- A
CSharpScript
for dynamic compilation with Roslyn
It can be virtually anything...
At least a From and a To mail address must be added.
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.From, "[email protected]", Encoding.UTF8));
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.ReturnReceiptTo, "[email protected]", Encoding.UTF8));
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.To, "{FirstName} {LastName} <{Email}>", Encoding.UTF8));
There is a special mailbox address type which is helpful for testing:
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.TestAddress, "[email protected]", Encoding.UTF8));
If MailAddressType.TestAddress
will be added, all recipient mailbox addresses will be replaced with the test mailbox address. The display names will be left unchanged. Remember to remove MailAddressType.TestAddress
after you've completed your tests.
Modern mail clients are able to deal with Encoding.UTF8
as the most widespread encoding for Unicode characters. Choose the Encoding
parameter which fits best to your mail clients abilities.
MailMergeMessage.PlainText
and MailMergeMessage.HtmlText
are fully independent from a technical viewpoint. Depending on the complexity of text formatting, special care should be given to the MailMergeMessage.PlainText
for a good reading experience.
For simple scenarios the MailMergeMessage.PlainText
can be automatically derived from the MailMergeMessage.HtmlText
:
mmm.ConvertHtmlToPlainText();
If the built-in converter does not fulfill your requirments, you can use your own by implementing the interface IHtmlConverter
.
mmm.ConvertHtmlToPlainText(mySpecialHtmlConverter);
An exciting matter about HTML text is, that you can enrich the text with images. MailMergeLib
will embed the images into the mail message for you.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Event offer for you, {FirstName}</title>
<base href="file:///../"/>
</head>
<body>
Dear {FirstName}:<br/>
Today we have special event offer for you:<br/>
<img src="{Image}" alt="Event Offer" width="100"/>
</body>
</html>
- Same as with plain text, HTML text may contain
{placeholders}
for variables. - For image files (and other attachment files) it is recommended to supply a base path to the location of the files, instead of using absolute paths for each image. This can be achieved by
<base href="..."/>
. However, it is better to codemmm.Config.FileBaseDirectory="path-to-files"
, because this path will be used for images and other attachment files. - The filename (
Image
is this example) may be a relative path. - The image HTML tag contains the placeholder
{Image}
which will be replaced with the variable value, e.g. "john.jpg". At the same time the image file will be added to the message as a "linked resource" and the image tag will change to<img src="cid:..."
. - If you would include any
<script>
tags, these would be removed.
What we should have in mind for HTML messages is to use
- static, table-based layouts - no responsive laylouts
- HTML tables which are nested as needed
- templates with a width of 600-800 pixels
- only simple, inline CSS
For inlining CSS there is a very good solution: PreMailer, available on NuGet, which works perfectly together with MailMergeLib
.
In a very simple way - all HTML is included in MailMergeMessage.HtmlText
- inlining CSS works like that:
var mmm = new MailMergeMessage(...); // create your mail message
mmm.HtmlText = "..."; // set your HTML part, using CSS
var result = PreMailer.MoveCssInline(mmm.HtmlText);
if (result.Warnings.Length > 0) { // process any warnings }
mmm.HtmlText = result.Html; // set the processed HTML with CSS inlined.
In a future version, we are considering to implement a hook to PreMailer
. They are also using AngleSharp
, so we could avoid to parse the HTML part twice, and make templates work as well.
Note: Currently PreMailer
unfortunately does not come with a constructor taking an AngleSharp
IHtmlDocument
as an argument.
Although it will be rarely necessary to add image files manually, but you can:
mmm.AddExternalInlineAttachment(new FileAttachment("filename.jpg", "cid-for-manual-inline-att"));
In this case, however, you'll also have to take care of the reference of the image tag:
<img src="cid:cid-for-manual-inline-att" />
Note: The way how to use the attachments covered in this section applies for pure plain text, HTML text and mixed text messages.
Taking our sample data source, adding a PDF file works like that:
mmm.Config.FileBaseDirectory="path-to-files";
mmm.FileAttachments.Add(new FileAttachment("{Attachment}", "Event.pdf", "application/pdf"));
- Use the
FileBaseDirectory
config setting instead of having absolute paths to files. - The constructor for a
FileAttachment
takes as parameters- the name of the file in the file system. The filename (
Attachment
is this example) may be a relative path. - the display name that the recipient of the mail message will see
- the mime type (optional).
MailMergeLib
is able to detect the corrent mime type for the most common file types.
- the name of the file in the file system. The filename (
Adding a StreamAttachment
instead of a FileAttachment
:
var fs = new FileStream("{Attachment}", FileMode.Open);
mmm.StreamAttachments.Add(new StreamAttachment(fs, "Display Name", "application/pdf"));
Sometimes it can be handy to add an attachment created from a string.
mmm.StringAttachments.Add(new StringAttachment("Some text content...", "DisplayName.txt"));
You could e.g. add a header which Microsoft Outlook honors as the expiration date of the message.
mmm.Headers.Add(HeaderId.Expires, Encoding.UTF8, DateTime.Now.AddDays(30).ToString("EEE, d MMM yyyy hh:mm:ss Z"));
All available headers are part of the HeaderId
enumeration.
Mail messages can easily be stored and restored to/from XML. The XML can be serialized to a file system file, a stream or a string.
mmm.Serialize("path-to-file.xml", Encoding.UTF8);
// and later:
mmm = MailMergeMessage.Deserialize("path-to-file.xml", Encoding.UTF8);