BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Network and Internet
.NET 2.0+

Sending SMTP Email Asynchronously

Sending email using the Simple Mail Transport Protocol (SMTP) can be a slow process, particularly when sending large numbers of messages using, for example, a bulk email tool. This process can be accelerated with considered use of asynchronous sending.

Sending SMTP Email Synchronously

Electronic mail can be delivered from .NET applications using the Simple Mail Transport Protocol (SMTP). This is the standard for sending email via the Internet. To learn how to send email, refer to the article, "Sending SMTP Email", which uses synchronous methods to deliver the messages to an SMTP server.

The delivery method described in the above article is simple and provides acceptable performance for a small number of emails. However, as each request blocks the calling thread, the program can spend a significant proportion of its time waiting for the SMTP server to respond.

Sending SMTP Email Asynchronously

If performance in an application is important and the synchronous method of sending email is causing a bottleneck, email can be delivered to an SMTP server asynchronously. Using this approach, a mail message is sent to the SMTP server using a separate thread so that the current thread is not blocked whilst it awaits a response. Depending upon the application, this can give a real or perceived performance gain by allowing the program to complete other tasks in parallel to the email operation.

SmtpClient.SendAsync Method

SMTP email can be sent using the SendAsync method of the SmtpClient class. This method is syntactically similar to the standard Send method with the additional of one parameter. The parameter permits a user token to be specified. The user token is an object of any type, usually used to uniquely identify the email. In the following sample program, the user token is a string containing the word "Test".

NB: Executing this code requires constants to be configured in the manner described in the article "Sending SMTP Email". The ReadLine call waits for the user to press Enter, which also provides a little time to allow the message to be sent before the program is terminated. In your own real-world applications, you should use another method of ensuring that the message has been delivered before exiting.

static void Main(string[] args)
{
    MailMessage message = new MailMessage();
    message.To.Add(RecipientEmail);
    message.From = new MailAddress(SenderEmail);
    message.Subject = "Asynchronous Email Test";
    message.Body = "This is a test email, sent asynchronously.";
    client.SendAsync(message, "Test");

    Console.WriteLine("Main program finished.");
    Console.ReadLine();
}

SendCompleted Event

As the SendAsync method executes on a separate thread to the main program, the completion of the emailing process is not immediately apparent. To allow you to determine if the email has been delivered, the SmtpClient class provides the SendCompleted event. This event is raised when the send operation is completed. The event signature includes event arguments in an AsyncCompletedEventArgs object, which includes status and error information and the user token initially provided to the SendAsync method.

If you are sending a number of electronic mail messages using the same SmtpClient object, it is important that you capture the SendCompleted event and use it to determine that the mailing operation is complete. If you do not, it is possible that the SmtpClient will be instructed to send two messages concurrently. This is not possible and causes an exception to be thrown.

We can capture the SendCompleted event by adding the following line to the Main method, just before the SendAsync method is executed.

client.SendCompleted += new SendCompletedEventHandler(MailDeliveryComplete);

This attaches a new method named "MailDeliveryComplete" to the SendCompleted event. The new method will simply read the status of the delivery and output it, along with the user token, to the console. The status and user token are retrieved by reading three properties of the event arguments passed in the event. These are:

  • Error. If an error occurs during delivery of the mail message, the Error property contains the details of the problem in an Exception object. If there is no error, this property is null.
  • Cancelled. It is possible to cancel the delivery of an email to the SMTP server. If the operation was cancelled, this Boolean property will be set to true.
  • UserState. The user token passed to the SendAsync method is held in this property.

Add the following method to the program to capture the SendCompleted event:

static void MailDeliveryComplete(object sender,
    System.ComponentModel.AsyncCompletedEventArgs e)
{
    Console.WriteLine("Message \"{0}\".", e.UserState);

    if (e.Error != null)
        Console.WriteLine("Error sending email.");
    else if (e.Cancelled)
        Console.WriteLine("Sending of email cancelled.");
    else
        Console.WriteLine("Message sent.");
}

You can now execute the program to see the results and send an email. The output from the program should be as follows, note that the program can finish before the email delivery is completed.

Main program finished.
Message "Test".
Message sent.
15 June 2008