Click here to Skip to main content
15,314,303 members
Articles / Web Development / HTML
Posted 10 Jul 2007


542 bookmarked

MailMergeLib - A Mail Client Library for .NET

Rate me:
Please Sign up or sign in to vote.
4.95/5 (131 votes)
5 Nov 2017MIT9 min read
MailMergeLib is an SMTP template mail client library written in C# which provides comfortable mail merge capabilities and SMTP fail-over features. If works on .NET Framework and .NET Core.

Image 1

Screenshot of a merged email

The Evolution

Back in 2007, after MailMergeLib was completed, it turned out that Microsoft System.Net.Mail had about 20 ugly issues. Many of them could be fixed by hacking their system with System.Reflection. The drawback was that every new release of the .NET Framework required extensive testing and rewriting the bug fixes.

The bugs were reported to Microsoft, and eventually half of them were corrected.

In the beginning of 2015, Jeffrey Stedfast introduced the first releases of his MimeKit and MailKit open source libraries. As he wrote in his Code Review, he was convinced that there could be something better than System.Net.Mail. And he really succeeded - not only in generating RFC compliant outgoing mail messages, but also in providing IMAP and POP3 facilities. This was the starting point for rewriting the code of MailMergeLib, now using MailKit and MimeKit instead of System.Net.Mail.


There are numerous occasions where an application has to send e-mails: Feedback forms in the web, webmailers, loggers and so forth. And there are many commercial solutions available: EASendMail SMTP Component, MailBee.NET SMTP Component, Aspose.Network.Mail or aspNetEmail, just to mention some of them. If you're looking for a free solution with source code, supplying comparable features, you'll find it worthwhile to have a closer look at MailMergeLib:

Mail Message Generation

  • Email templates can be fully individualized in terms of recipients, subject, HTML and/or plain text, attachments and even headers. Placeholders are inserted as variable names from data source between curly braces like so: {MailboxAddress.Name} or with formatting arguments like {Date:yyyy-MM-dd}. (In the first releases of MailMergeLib, this was accomplished with regular expressions. Now the extremely fast SmartFormat parser is implemented.)
  • HTML text may contain images from local hard disk, which will be automatically inserted as inline attachments.
  • For HTML text MailMergeLib can generate a plain text representation.
  • Attachment sources can be files, streams or strings.
  • The data source for email merge messages to a number of recipients and can be any IEnumerable object as well as DataTables. The data source for single emails can be any of the following types: Dictionary<string,object>, ExpandoObject, DataRow, any class instances or anonymous types. For class instances, it's even allowed to use the name of parameter less methods.
  • Placeholders in the email can be formatted with any of the features known from string.Format by using SmartFormat.NET. SmartFormat is a parser coming close to string.Format's speed, but bringing a lot of additional options like easy pluralization for many languages.
  • Resulting emails are MimeMessages from MimeKit, an outstanding tool for creating and parsing emails, covering all relevant MIME standards making sure that emails are not qualified as SPAM.
  • Support for international email address format.

Sending Email Messages

  • Practically unlimited number of parallel tasks to send out individualized emails to a big number of recipients.
  • SmptClients for each task can get their own preconfigured settings, so that e.g. several mail servers can be used for one send job.
  • Progress of processing emails can easily be observed with a number of events.
  • SMTP failures can automatically be resolved supplying a backup configuration. This fault-tolerance is essential for unattended production systems.
  • SMTP configuration can be stored/restored to/from standard XML files.
  • Emails are sent using the SmptClients from MailKit, the sister project to MimeKit. MailKit is highly flexible and can be configured for literally every scenario you can think of.
  • Instead of sending, emails can also be stored in MIME formatted text files, e.g. if a "pickup directory" from IIS or Microsoft Exchange shall be used. If needed, these files can be loaded back into a MimeMessage from MimeKit.


  • Fine grained control over the whole process of email message generation and distribution.
  • Clearly out-performs .NET System.Net.Mail.
  • Configuration settings for messages and SMTP can be stored to and loaded from an XML file.
  • RFC standards compliant.
  • We ask you not to use MailMergeLib for sending unsolicited bulk email.

Using the Code


Basic Settings

The configuration of MailMergeLib consists of two major parts: MessageConfig and SenderConfig.

First of all, set the key which is used to encrypt and decrypt network credentials when the configuration is saved to file. This is not absolutely safe, but better than showing credentials as plain text:

Settings.CryptoKey = "SecretCryptoKey";  // don't use this key

A rather minimal configuration looks like this:

var settings = new Settings
    MessageConfig =
        CharacterEncoding = Encoding.UTF8,
        StandardFromAddress = new MailboxAddress("sender name", ""),
        // necessary for proper formatting of placeholders:
        CultureInfo = CultureInfo.CurrentCulture,
        // especially in case a placeholder results in an empty address:
        IgnoreIllegalRecipientAddresses = true,
        Xmailer = "MailMergeLib 5"
    SenderConfig =
        SmtpClientConfig = new[]
            new SmtpClientConfig()
                MessageOutput = MessageOutput.SmtpServer,
                SmtpHost = "",
                SmtpPort = 587,
                NetworkCredential = new Credential("user", "password"),
                // identify active configuration in case you have more than one
                Name = "StandardConfig",
                // number of trials until an exception is thrown:
                MaxFailures = 3,  
                // number of milliseconds before a retry to send will happen:
                RetryDelayTime = 1000,   
                // number of milliseconds between messages:
                DelayBetweenMessages = 0, 
                // used in SMTP Hello command
                ClientDomain = ""  

Settings can be saved and restored:

var settings = Settings.Deserialize("MailMergeLib.config");

Event Handlers

MailMergeSender allows for custom event handlers. MailMergeSender will raise events OnBeforeSend, OnAfterSend, OnSendFailure, OnMergeBegin, OnMergeComplete, and OnMergeProgress. Example:

var mms = new MailMergeSender {Config = settings.SenderConfig};
mms.OnAfterSend += (sender, args) => { // do something useful here };

Create a New Message

The Data Source for a Mail Message

Of course, the data source is the most important topic for mail merging.

First, let's create a Dictionary which will contain the values for {placeholders} in the message. Placeholders are the names in curly braces of e.g. IList item properties, or the column names of a data table.

var variables = new Dictionary<string, object>() 
{ { "Email", "" }, {"Name", "John Specimen"} };

{placeholders} can be used in email addresses, in the subject, in the plain text or HTML body, in text attachment content and in attachment names (including embedded images of the HTML body).

So in case of 2 recipients, you could create an anonymous type:

var variables = new[]
        new {Email = "", Name = "John Specimen"}
        new {Email = "", Name = "Mary Specimen"}

When using O/R mappers, an entity field could look like this: Department.Leader.FirstName. So you could use the field name as a placeholder with "dot notation": {Department.Leader.FirstName}.

Message Body

Next, we create a new message with a subject, plain text and an HTML body part.

var mmm = new MailMergeMessage("Personal subject for {Name}", "This is pure text for {Name}",
            "<html><head><title>No title</title></head>
            <body>This is HTML text for {Name}</body></html>") {Config = settings.MessageConfig};

In case the HTML part contains an image, MailMergeLib will automatically add it to the email as a "linked resource". The image source must contain the path to a local file. The path may contain {placeholders} as well.

<img src="file:///full-path-to-your-image-file.jpeg" alt="Image" width="100" height=100"/>

Instead of supplying the full path for each image, it's possible to set the path for images:

mmm.Config.FileBaseDirectory = "Path-to-images";

You want to see how the final message will look like? Just save it to a file and explore it with a text editor or your email application (e.g. Microsoft Outlook or Mozilla Thunderbird):


If the plain text part should not be supplied manually, MailMergeLib can do the work to convert HTML to plain text:

mmm.PlainText = mmm.ConvertHtmlToPlainText();

To do this job, MailMergeMessage supplies the ParsingHtmlConverter for converting HTML to plain text. It uses the open source library AngleSharp^ and has a similar approach like Markdown^ by John Gruber. It converts the most common HTML tags and attributes which appear in emails, not on web pages, to plain text with quite good results. If AngleSharp is not available or fails, the very basic RegExHtmlConverter is used (similar to this solution^), unless you provide your custom converter implementing IHtmlConverter.

Formatting Capabilities

The placeholders and the formatting capabilities allows separation of code and design. In order to change the content of an email, just change the template file(s) for the plain or HTML text and you're done without a need to touch your code.

Generally, formatting of {placeholders} is fully compatible with string.Format by means of SmartFormat.Net which is built into MailMergeLib. For details, please refer to the SmartFormat Wiki. SmartFormat.Net is exposed as the SmartFormatter property of a MailMergeMessage.

Here are some examples which have an equivalent to string.Format:

"{Date:yyy-MM-dd}"  for a variable of type DateTime
"You are visitor number {NumOfVisitors}"  for a variable of type int
"{Name} from {Address.City}, {Address.State}"  for a variable which is an instance of class "user"

Formatting extensions coming with SmartFormat.Net:

"You have {emails.Count} new {emails.Count:message|messages}"  // pluralization
"{Users:{Name}|, |, and } liked your comment"  // a list of users
"{Name:choose(null|):N/A|empty|{Name}}"        // assuming an object with property "Name" 
                                               // which can be null, empty or a string


You may also want to add some individualized attachments by adding placeholders to the file name. E.g.:

    (new FileAttachment("testmail_{Username}.pdf", "sample.pdf", "application/pdf"));

And that's the way to add string attachments:

mmm.StringAttachments.Add(new StringAttachment
    ("Some programmatically created content", "logfile.txt", "text/plain"));

Mail Addresses

For sending a mail, we need to supply at least one recipient's address and the sender's address. Again, using placeholders makes it possible to create individualized emails.

mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.From, ""));
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.To, "{Name}", "{Email}"));


If you're using a data source with variables, it may well happen that you have recipients with empty e-mail fields. That's why you may want to not throw an exception with empty addresses.

mmm.Config.IgnoreEmptyRecipientAddr = true;

Want to change MailMergeLib's identification? Set the mail's Xmailer header to anything you like.

mmm.Config.Xmailer = "MailMergeLib 5.0";

Sending a Message

Using the MailMergeSender is quite straight forward: Create instance of the class and provide some settings explained in the Configuration chapter.

Creating a configured MailMergeSender

Setup the mail sender:

var mailSender = new MailMergeSender {Config = settings.SenderConfig};

Start the Transfer

For the Send job, there are several alternatives:

  1. Send a single message as an asynchronous operation:
    var dict = new Dictionary<string, object>() 
    { { "Email", "" }, {"Name", "John Specimen"} };
    mailSender.SendAsync(mmm, (object) dict);
  2. Send all messages for all items in the DataSource as an asynchronous operation:
    var variables = new[]
         new {Email = "", Name = "John Specimen"}
         new {Email = "", Name = "Mary Specimen"}
     mailSender.SendAsync(mmm, variables);
  3. Send messages as a synchronous operation for all items in the DataSource:
    mailSender.Send(mmm, variables);
  4. Or just send a single message providing a Dictionary with name/value pairs synchronously:
    mailSender.Send(mmm, (object) dict);

SMTP Fail-over Configuration

When you define more than one SMTP configurations in the SenderConfig, then the first SMTP configuration will be the standard one used to send messages. The second one will be used in case sending over the standard configuration will fail.

This can be extremely useful in unattended environments (e.g. a scheduled task on a web server).

SenderConfig =
    SmtpClientConfig = new[]
        new SmtpClientConfig()
            MessageOutput = MessageOutput.SmtpServer,
            SmtpHost = "",
            SmtpPort = 25,
            NetworkCredential = new Credential("user", "password"),
            Name = "Standard Config",
            MaxFailures = 3,
            DelayBetweenMessages = 500
        new SmtpClientConfig()
            MessageOutput = MessageOutput.SmtpServer,
            SmtpHost = "",
            SmtpPort = 587,
            NetworkCredential = new Credential("user2", "password2"),
            Name = "Backup Config",
            DelayBetweenMessages = 1000
    MaxNumOfSmtpClients = 5

Using More than One SmtpClient for Sending Messages

Setting mailSender.Config.MaxNumOfSmtpClients = 5 will use five parallel SmtpClients for sending messages asynchronously.

When defining more than one SMTP configuration, each of the configurations will be assigned alternating to the SmtpClients. Fail-over will also work slightly differently: in case of failure, the first configuration other than the current one will be used.

Cancelling a Send Operation

Asynchronous Send operations can be cancelled at any time:


Influencing Error Handling

Timeout in milliseconds:

mailSender.Config.Timeout = 100000;

Maximum number of failures until sending a message will finally fail:

mailSender.Config.MaxFailures = 3;

Retry delay time between failures:

mailSender.Config.RetryDelayTime = 3000;

Delay time between each message:

mailSender.Config.DelayBetweenMessages = 1000;


The new version of MailMergeLib is using MimeKit and MailKit. They are excellent open source libraries which give a very fine grained control over the whole process of email message generation and distribution. And last but not the least, they produce RFC standards compliant email messages.

It is recommended to migrate from former versions to MailMergeLib version 5.

Special Thanks To

  • Jeffrey Stedfast for his MimeKit and MailKit open source libraries
  • Florian Rappl for his open source AngleSharp HTML parser
  • John Gruber for sharing his Markdown xslt-based text-to-HTML conversion tool
  • All users giving their feedback and votes in the forum


  • 2007-07-10: Initial public release MailMergeLib 2.0 using System.Net.Mail
  • 2009-12-23: MailMergeLib 3.0 using System.Net.Mail
  • 2010-05-01: MailMergeLib 4.0 using System.Net.Mail
  • 2016-09-04: MailMergeLib 5.0 - a major rewrite using MimeKit and MailKit for low level operations
  • 2016-10-23: Since MailMergeLib 5.1.0 also supporting .NET Core

The latest version of MailMergeLib is available on GitHub:


This article, along with any associated source code and files, is licensed under The MIT License


About the Author

Germany Germany
No Biography provided

Comments and Discussions

GeneralRe: Is subject enconding really the problem? Pin
PepitoPerezRamos28-Jul-10 9:05
MemberPepitoPerezRamos28-Jul-10 9:05 
NewsRe: Problem with subject enconding Pin
axuno8-Aug-10 6:21
Memberaxuno8-Aug-10 6:21 
QuestionRe: Problem with subject enconding Pin
floritheripper29-Sep-10 23:37
Memberfloritheripper29-Sep-10 23:37 
AnswerRe: Problem with subject enconding Pin
axuno3-Oct-10 23:09
Memberaxuno3-Oct-10 23:09 
GeneralRe: Problem with subject enconding Pin
floritheripper4-Oct-10 22:43
Memberfloritheripper4-Oct-10 22:43 
AnswerSolved: Problem with subject enconding Pin
axuno5-Oct-10 5:52
Memberaxuno5-Oct-10 5:52 
GeneralRe: Solved: Problem with subject enconding Pin
floritheripper6-Oct-10 1:28
Memberfloritheripper6-Oct-10 1:28 
QuestionThere are some news about the issue System.Net.Mail only supports “Explicit SSL” ? Pin
riccardo685-Jul-10 22:05
professionalriccardo685-Jul-10 22:05 
The issue is well explained in the post[^]
AnswerRe: There are some news about the issue System.Net.Mail only supports “Explicit SSL” ? Pin
axuno6-Jul-10 10:39
Memberaxuno6-Jul-10 10:39 
GeneralAttachments with special characters are not sent correctly Pin
William RiP28-Jun-10 21:51
MemberWilliam RiP28-Jun-10 21:51 
AnswerWorkaround: Attachments with special characters are not sent correctly Pin
axuno2-Jul-10 0:31
Memberaxuno2-Jul-10 0:31 
QuestionVS 2005 version? Pin
Member 358175317-Jun-10 13:39
MemberMember 358175317-Jun-10 13:39 
AnswerRe: VS 2005 version? Pin
axuno18-Jun-10 19:31
Memberaxuno18-Jun-10 19:31 
GeneralRe: VS 2005 version? Can I ask a question? Pin
Member 358175319-Jun-10 5:22
MemberMember 358175319-Jun-10 5:22 
GeneralRe: VS 2005 version? Including images (inline attachments) Pin
axuno23-Jun-10 7:57
Memberaxuno23-Jun-10 7:57 
QuestionProblem with html mail Pin
Gismow19-May-10 5:51
MemberGismow19-May-10 5:51 
GeneralRe: Problem with html mail Pin
axuno22-May-10 0:00
Memberaxuno22-May-10 0:00 
AnswerRe: Problem with html mail Pin
Gismow25-May-10 0:22
MemberGismow25-May-10 0:22 
AnswerProblem with html mail: Resolved Pin
axuno7-Jun-10 11:22
Memberaxuno7-Jun-10 11:22 
Generalcompile error with Visual Studio 2005 Pin
SaschaGottfried11-May-10 4:30
MemberSaschaGottfried11-May-10 4:30 
GeneralNo more Visual Studio 2005 support Pin
axuno12-May-10 6:03
Memberaxuno12-May-10 6:03 
QuestionSystem.Net.Mail.MailMessage - return-path problem, is it solved ? Pin
morSchmidt4-May-10 0:27
MembermorSchmidt4-May-10 0:27 
AnswerRe: System.Net.Mail.MailMessage - return-path problem, is it solved ? Pin
axuno4-May-10 12:06
Memberaxuno4-May-10 12:06 
GeneralRe: System.Net.Mail.MailMessage - return-path problem, is it solved ? Pin
morSchmidt7-May-10 3:57
MembermorSchmidt7-May-10 3:57 
AnswerRe: System.Net.Mail.MailMessage - return-path problem, is it solved ? Pin
axuno7-May-10 4:40
Memberaxuno7-May-10 4:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.