Send Emails Asynchronously

If you have built any kind of workflow type application, you will have encountered the need to send emails from your application as part of a string of actions. Sending these emails can often be a bottleneck in your workflow and cause the application to stall temporarily whilst the STMP client is instantiated, the email is generated and sent, then confirmation is returned. I will discuss a better way to do this within an MVC application.

In this article, I will use the built-in SmtpClient() class to generate the emails. I find this class the easiest to use and I use it within most applications that I build. So this article will discuss the SmtpClient.Send method for sending emails. I need to mention that the SmtpClient class has another method available for sending emails. It is the SmptClient.SendAsync method. This method "does not block the calling thread and allows the caller to pass an object to the method that is invoked when the operation completes". However, I abstract my email handler to a separate class in my application (not generated within an event handler in a single page). So, SmptClient.SendAsync is not an option for my MVC ViewModel builders. Instead, I tell C# to send the email on a separate thread so that the process does not hold up the workflow.

Let's take a normal SmtpClient call like the one below:

using (SmtpClient client = new SmtpClient())
{
	client.Port = SMTPServerPort;
	client.Host = SMTPServerName;
	client.EnableSsl = SMTPUseSSL;
	client.UseDefaultCredentials = SMTPUseDefaultCredentials;
	client.DeliveryMethod = SmtpDeliveryMethod.Network;
	client.Credentials = new NetworkCredential(SMTPUserName, SMTPPassword);
	client.Send(MailMessage);
}

The send method at line 9 will send the email, but C# will wait until the email is sent (successfully or not) before continuing on with the next line of code. This can cause a pause of several seconds and may leave the user wondering what is happening.

Instead, let's look at this code. It is the same using statement as above, but now we wrap it in a ThreadPool.QueueUserWorkItem block.

ThreadPool.QueueUserWorkItem(o =>
{
	using (SmtpClient client = new SmtpClient())
	{
		client.Port = SMTPServerPort;
		client.Host = SMTPServerName;
		client.EnableSsl = SMTPUseSSL;
		client.UseDefaultCredentials = SMTPUseDefaultCredentials;
		client.DeliveryMethod = SmtpDeliveryMethod.Network;
		client.Credentials = new NetworkCredential(SMTPUserName, SMTPPassword);
		client.Send(MailMessage);
	}
});

This approach will queue the method for execution and not cause the C# to wait while the email is sent - QueueUserWorkItem

So now we can make our email process asynchronous because the actual email delivery is handled by a different thread than the MVC process which is running in our application.

Another thing to bear in mind is error notification. This code has no way to inform the user that an error has occurred or whether the email was successfully sent or not. Maybe that is something you could try to build and add to the comments below.

Til next time ...