Click here to Skip to main content
15,897,718 members
Articles / Web Development / HTML

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 844.1K   10.2K   542  
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.
using System;
using System.Data;
using System.Text;
using System.Windows.Forms;
using MailMergeLib;


namespace MailMergeTest
{
    /// <summary>
    /// Very basic sample application 
    /// in order to show how MailMergeLib can be used.
    /// </summary>
    /// <example>
    /// Have a look at method btnSend_Click:
    /// 
    /// Send using an array of anonymous type:
    /// _mmm.DataSource = CreateAnonymousDataList();
    /// 
    /// Or send using a simple data table:
    /// _mmm.DataSource = CreateDataTable();
    /// </example>
    public partial class FrmMain : Form
    {
        private MailMergeSender _mailSender;
        private MailMergeMessage _mmm;
    	private string _outputFolder;

        public FrmMain()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        	_outputFolder = System.IO.Path.GetTempPath() + @"\mail";
			if (!System.IO.Directory.Exists(_outputFolder)) 
				System.IO.Directory.CreateDirectory(_outputFolder);

			if (DialogResult.Cancel == MessageBox.Show("Mail output will be written into the folder\n" + _outputFolder + "\nand the folder will open in Windows Explorer", "Please note", MessageBoxButtons.OKCancel))
			{
				Application.Exit();
				return;
			}

        	// open the output folder in new windows explorer window
			System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
			{
				FileName = _outputFolder,
				UseShellExecute = true,
				Verb = "open"
			});

            Setup();
        }

        private void Setup()
        {
            // read content
            string html = ReadHtmlText();

            // insert your own e-mail address here!
            MailMergeAddress myMailAddress = new MailMergeAddress(MailAddressType.TestAddress, "my@mail.com", "My Name", Encoding.Default);

            // create the mail message
			_mmm = new MailMergeMessage("CRON Job Status Report for Domain '{DomainName:\"{0}{empty:[name not registered!]}\"}'", null, html);
        	_mmm.PlainText = _mmm.ConvertHtmlToPlainText();

            // adjust mail specific settings
            _mmm.CharacterEncoding = Encoding.GetEncoding("iso-8859-1");
            _mmm.CultureInfo = new System.Globalization.CultureInfo("en-US");
            _mmm.TextTransferEncoding = System.Net.Mime.TransferEncoding.SevenBit;
            _mmm.BinaryTransferEncoding = System.Net.Mime.TransferEncoding.Base64;

            // add recipients, from address and test address to use.
            // the address part of the test address will be used instead of the other addresses.
            _mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.To, "<{AdminEmail}>", "{AdminName}", Encoding.Default));
            _mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.From, myMailAddress.Address, myMailAddress.DisplayName, Encoding.Default));
            _mmm.MailMergeAddresses.Add(myMailAddress);

			// add a file attachment - missing file "cron_logfile Shirley.pdf" will deliberately produce an error
			_mmm.FileAttachments.Add(new FileAttachment(@"cron_logfile {AdminName}.pdf", @"cron_logfile {AdminName}.pdf", "application/pdf"));

            // add a string attachment
            _mmm.StringAttachments.Add(new StringAttachment("Some programmatically created content", "file.txt", "text/plain"));

            // base directory for html images
            _mmm.FileBaseDir = GetMailDemoFilesDir();

            // setup the mail sender
            _mailSender = null;
            _mailSender = new MailMergeSender();

            SetupEventHandlers();

            _mailSender.LocalHostName = "mail." + Environment.MachineName;
            _mailSender.MaxFailures = 1;
            _mailSender.DelayBetweenMessages = 1000;

			_mailSender.MailOutputDirectory = _outputFolder;
            _mailSender.MessageOutput = MessageOutput.Directory;  // change to MessageOutput.SmtpServer if you like, but be careful :)

            // smtp details - change to your demands
            _mailSender.SmtpHost = "mail.server.com";
            _mailSender.SmtpPort = 25;
            _mailSender.SetSmtpAuthentification("username", "password");
            _mailSender.LocalHostName = "my.localhostname.com";
        }


        private void Send()
        {
            progress.Minimum = 0;
            progress.Maximum = _mmm.DataItemCount;
            progress.Step = 1;
			progress.Value = 0;

            txtMerge.Clear();
            textBox1.Clear();
            textBox2.Clear();

            btnCancel.Enabled = true;

			if (!System.IO.Directory.Exists(_outputFolder))
				System.IO.Directory.CreateDirectory(_outputFolder);

            try
            {
                _mailSender.SendAllAsync(_mmm);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex.Message + " " + ex.Source);
            }
        }


        private string ReadHtmlText()
        {
            return ReadTextFile(GetMailDemoFilesDir() + @"\cron_testmail.html");
        }

		private string ReadTextFile(string file)
		{
			using (System.IO.StreamReader sr = new System.IO.StreamReader(file))
			{
				return sr.ReadToEnd();
			}
		}

        private string GetMailDemoFilesDir()
        {
            return System.IO.Path.GetFullPath(Application.StartupPath + @"..\..\MailDemoFiles");
        }

        private DataTable CreateDataTable()
        {
            DataTable dt = new DataTable("Table");
			dt.Columns.Add("AdminEmail", typeof(string));
			dt.Columns.Add("AdminName", typeof(string));
        	dt.Columns.Add("DomainName", typeof (string));
			dt.Columns.Add("JobEndDateTime", typeof(DateTime));
            dt.Columns.Add("IncludeFile", typeof(string));
			dt.Rows.Add(new object[] { "harry@mail.com", "Harry", "example1.com", DateTime.Now, "cron_testmail_includefile.txt" });
			dt.Rows.Add(new object[] { "jeff@mail.com", "Jeff", "example2.com", DateTime.Now.AddDays(-11), "cron_testmail_includefile.txt" });
			dt.Rows.Add(new object[] { "liz@mail.com", "Liz", "", DateTime.Now.AddHours(5), "cron_testmail_includefile.txt" });
			dt.Rows.Add(new object[] { "shirley@mail.com", "Shirley", "example4.com", DateTime.Now, "cron_testmail_includefile.txt" });

			dt.Columns["JobEndDateTime"].ExtendedProperties.Add("format", "{0:F}");

            return dt;
        }

        private object CreateAnonymousDataList()
        {
			return new[] {
               new
                   {
                       AdminEmail = "harry2@mail.com",
                       AdminName = "Harry",
					   DomainName = "example1.com",
                       JobEndDateTime = DateTime.Now,
                       IncludeFile = "cron_testmail_includefile.txt"
                   },
               new
                   {
                       AdminEmail = "jeff2@mail.com",
                       AdminName = "Jeff",
					   DomainName = "example3.com",
                       JobEndDateTime = DateTime.Now.AddDays(-11),
                       IncludeFile = "cron_testmail_includefile.txt"
                   },
               new
                   {
                       AdminEmail = "liz2@mail.com",
                       AdminName = "Liz",
					   DomainName = "example4.com",
                       JobEndDateTime = DateTime.Now.AddHours(5),
                       IncludeFile =  "cron_testmail_includefile.txt"
                   },
               new
                   {
                       AdminEmail = "shirley2@mail.com",
                       AdminName = "Shirley",
					   DomainName = "example4.com",
                       JobEndDateTime = DateTime.Now,
                       IncludeFile = "cron_testmail_includefile.txt"
                   }
           };
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            _mailSender.SendCancel();
            _mailSender = null;
            btnCancel.Enabled = false;
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            btnSend.Enabled = false;
        	lblDelayTime.Text = string.Format("Delay between messages: {0} ms.", _mailSender.DelayBetweenMessages);
            Setup();

			// Send using an array of anonymous type
			_mmm.DataSource = CreateAnonymousDataList();
			// Send using a DataTable
			// _mmm.DataSource = CreateDataTable();

            Send();
        }

		private void SetupEventHandlers()
        {
            #region SetEventHandlers
            _mailSender.OnBeforeSend += ((obj, args) =>
                                             {
                                                 string text = "Before: " +
                                                               args.MailMergeMessage.MailMergeAddresses.ToString(
                                                                   MailAddressType.To);
                                                 if (textBox1.InvokeRequired)
                                                 {
                                                     textBox1.Invoke(
                                                          (new MethodInvoker(() => textBox1.Text += text + Environment.NewLine)));
                                                 }
                                                 else
                                                 {
                                                     textBox1.Text += text + Environment.NewLine;
                                                 }
                                             });
            _mailSender.OnAfterSend += ((obj, args) =>
                                            {
                                                string text = "After: " +
                                                              args.MailMergeMessage.MailMergeAddresses.ToString(
                                                                  MailAddressType.To) +
                                                              (args.Error != null ? args.Error.Message : "");
                                                if (textBox1.InvokeRequired)
                                                {
                                                    textBox1.Invoke(
                                                        (new MethodInvoker(() => textBox1.Text += text + Environment.NewLine)));
                                                }
                                                else
                                                {
                                                    textBox1.Text += text + Environment.NewLine;
                                                }
                                            });
            _mailSender.OnSendFailure += ((obj, args) =>
                                              {
                                                  string errorMsg = args.Error.Message;
                                                  MailMergeMessage.MailMergeMessageException ex = args.Error as MailMergeMessage.MailMergeMessageException;
                                                  if (ex != null && ex.Exceptions.Count > 0)
                                                  {
                                                      errorMsg = string.Format("{0}", ex.Exceptions[0].Message);
                                                  }
                                                  string text = string.Format("Error: {0}", errorMsg);
                                                  if (textBox2.InvokeRequired)
                                                  {
                                                      textBox2.Invoke(
                                                          (new MethodInvoker(() => textBox2.Text += text + Environment.NewLine)));
                                                  }
                                                  else
                                                  {
                                                      textBox2.Text += text + Environment.NewLine;
                                                  }
                                              });

            _mailSender.OnMergeBegin += ((obj, args) =>
                                             {
                                                 string text = string.Format("MergeStarttime: {0} - ", args.StartTime.ToString());
                                                 if (txtMerge.InvokeRequired)
                                                 {
                                                     txtMerge.Invoke(new MethodInvoker(() => txtMerge.Text += text + Environment.NewLine));
                                                 }
                                                 else
                                                 {
                                                     txtMerge.Text += text + Environment.NewLine;
                                                 }
                                             });
            _mailSender.OnMergeComplete += ((obj, args) =>
                                                {
                                                    string text = string.Format("MergeEndTime: {0}", args.EndTime.ToString());
                                                    if (txtMerge.InvokeRequired)
                                                    {
                                                        txtMerge.Invoke(new MethodInvoker(() =>
                                                                                             {
                                                                                                 txtMerge.Text += text + Environment.NewLine;
                                                                                                 btnSend.Enabled = true;
                                                                                             }));
                                                    }
                                                    else
                                                    {
                                                        txtMerge.Text += text + Environment.NewLine;
                                                        btnSend.Enabled = true;
                                                    }
                                                });
            _mailSender.OnMergeProgress += ((obj, args) =>
                                                {
                                                    string text = string.Format("Total: {0} / Sent: {1} / Error: {2}", args.TotalMsg, args.SentMsg,
                                                                                args.ErrorMsg);
                                                    if (progress.InvokeRequired)
                                                    {
                                                        progress.Invoke(new MethodInvoker(() => progress.PerformStep()));
                                                        label1.BeginInvoke(new MethodInvoker(() => label1.Text = text));
                                                    }
                                                    else
                                                    {
                                                        progress.PerformStep();
                                                        label1.Text = text;
                                                    }
                                                });
            #endregion
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions