TEAM IM Insights

Sending Custom Emails using C#

Written by Fletcher Thomas | Jun 4, 2024 5:59:26 AM

Are you developing a .NET application using C# and need the ability to send custom emails?  Look no further.  One of the beauties of .NET is the bounty of (often) free to use libraries available via Nuget.  My favorite for sending emails is MailKit which is provided under the MIT License.  We will start with some prerequisites and then get into a code sample:

  1. SMTP Server - details are out of scope, but your company likely has one as part of common cloud subscriptions like Microsoft, Google, Amazon, etc.
    1. Note that this can affect the address from which emails are allowed to be sent
  2. Application built using C# in Visual Studio
  3. Import MailKit library using Nuget (4.6.0 was used here)
  4. Server for hosting your application - in our case, this is most often M-Files
    1. Brief tangent: if you're familiar with M-Files, you may be wondering why we wouldn't use out of the box functionality for sending emails.  A few good reasons:
      1. Ability to include recipients who are not M-Files users in a single email, including CC and BCC
      2. Direct attachments rather than links to M-Files
      3. Sending emails from a different address than an M-Files server - this is especially relevant in the cloud

Make sure that connection details for SMTP are stored securely and ideally easy to update when needed.  For M-Files, this means putting them in configuration and masking the password field.  The below code sample refers to a Configuration class, but you can simply replace it with where you have stored your SMTP settings as needed:

 

using System;
using MimeKit;
using MailKit.Net.Smtp;

namespace local_testing
{
    static class SMTP
    {
        public static Configuration Configuration;
        public static bool TrySendSmtpMessage(string subject, string body, string[] toEmails, string[] ccEmails, string[] bccEmails, string[] filepaths)
        {
            var message = new MimeMessage();
            message.From.Add(new MailboxAddress(
                Configuration.SMTP_FROM_NAME,
                Configuration.SMTP_FROM_EMAIL // providing an invalid address can result in errors and/or spam alerts
            ));

            foreach (string email in toEmails)
            {   // First param can be set to recipient's name
                message.To.Add(new MailboxAddress(email, email));
            };
            
            foreach (string email in ccEmails)
            {
                message.Cc.Add(new MailboxAddress(email, email));
            }

            foreach (string email in bccEmails)
            {
                message.Bcc.Add(new MailboxAddress(email, email));
            }
            message.Subject = subject;
            var builder = new BodyBuilder
            {
                HtmlBody = body
            };
            ContentType ct = new ContentType("application", "octet-stream");
            foreach (string path in filepaths)
            {   // Note that you may run into errors trying to include more than about 10MB of attachments depending on your mail server
                builder.Attachments.Add(path, ct);
            }
            message.Body = builder.ToMessageBody();

            try
            {   
                using (SmtpClient client = GetClient())
                {
                    client.Send(message);
                    client.Disconnect(true);
                }
                return true;
            }
            catch (Exception e)
            {
                // Do something to handle errors
                throw e;
            }
            finally
            {
                // Clean up temporary file downloads if needed
            }
        }
        private static SmtpClient GetClient()
        {
            var client = new SmtpClient();
            client.Connect(Configuration.SMTP_HOST, Configuration.SMTP_PORT);
            if (!Configuration.USE_SIMPLE_MAIL)
            {   // Simple mail may be used for on-prem servers with necessary security in place but most servers will require authentication
                client.Authenticate(Configuration.SMTP_USERNAME, Configuration.SMTP_PASSWORD);
            }
            return client;
        }
    }
}