Handle Callbacks in Asynchronous Emails in ASP.NET

When we need to send bunch of emails, sending them synchronously will take much time. So one way to solve this problem is to send emails asynchronously. Sending emails asynchronously is very simple. And to handle call backs we need to associate one method to SendCompletedEventHandler. It will be called once the email has been sent. We need one smtp network host provider which will be configured in Smtp.config or Web.config. The sample code looks as below.
  1. public void SendEmailsAsync()   
  2. {  
  3.     var smtpSection = (SmtpSection) ConfigurationManager.GetSection("system.net/mailSettings/smtp");  
  4.     var mailClient = new SmtpClient(smtpSection.Network.Host);  
  5.     mailClient.SendCompleted += new SendCompletedEventHandler(SendCompleted);  
  6.     mailClient.EnableSsl = false;  
  7.     var mailMessage = new MailMessage("sender email""to address")   
  8.     {  
  9.         IsBodyHtml = true,  
  10.         Subject = "subject",  
  11.         Body = "body"  
  12.     };  
  13.     Object obj = meilMessage;  
  14.     mailClient.SendAsync(mailMessage, obj);  
  15. }  
  16.   
  17. public void SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) {  
  18.   
  19.     if (!e.Cancelled && e.Error != null)   
  20.     {  
  21.         //"Mail sent successfully"    
  22.     }  
  23. }  
In the above example we are reading smpt configurations from  smtp.config. You need to define network host which will take care of sending emails. The configuration looks as below. 
  1. <?xml version="1.0"?>  
  2. <smtp from="sender email id">  
  3.     <network host="Your smtp host name" />  
  4. </smtp>  
If you are calling  SendEmailsAsync() in a for loop then the main thread will not wait until all call back completed. It will exit immediately. So here we need to handle wait mechanism. The final code to handle this will be as below. 
  1. public void SendEmailsAsync()   
  2. {  
  3.     int remainingCalls = 0;  
  4.     public object RemainingCallLock = new object();  
  5.     for (int i = 0; i < noOfEmails; i++)   
  6.     {  
  7.   
  8.         var smtpSection = (SmtpSection) ConfigurationManager.GetSection("system.net/mailSettings/smtp");  
  9.         var mailClient = new SmtpClient(smtpSection.Network.Host);  
  10.         mailClient.SendCompleted += new SendCompletedEventHandler(SendCompleted);  
  11.         mailClient.EnableSsl = false;  
  12.         var mailMessage = new MailMessage("sender email""to address")   
  13.         {  
  14.             IsBodyHtml = true,  
  15.             Subject = "subject",  
  16.             Body = "body"  
  17.         };  
  18.         Object obj = meilMessage;  
  19.         mailClient.SendAsync(mailMessage, obj);  
  20.         RemaingingCalls++;  
  21.     }  
  22.     if (RemaingingCalls > 0) WaitHandle.WaitOne();  
  23.   
  24. }  
  25.   
  26. public void SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)   
  27. {  
  28.   
  29.     if (!e.Cancelled && e.Error != null)   
  30.     {  
  31.         //"Mail sent successfully"      
  32.         lock(RemainingCallLock) {  
  33.             if (--RemaingingCalls == 0)   
  34.             {  
  35.                 WaitHandle.Set();  
  36.             }  
  37.         }  
  38.     }  
  39. }  
In the above example WaitHandle.WaitOne() will pause the current thread until all requested are handled. Once all requests are handled we are releasing the lock by calling WaitHandle.Set().