0

I am using SendAsync to send an email. The reason I'm using async is simply to free up the UI rather than send multiple emails.

I have created the following callback event:

    static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        var client = sender as SmtpClient;
        var message = e.UserState as MailMessage;

        if (e.Error.IsNotNull())
        {
            if (e.Error is SmtpFailedRecipientException)
            {
                var status = ((SmtpFailedRecipientException)(e.Error)).StatusCode;

                if (status == SmtpStatusCode.MailboxBusy ||
                    status == SmtpStatusCode.MailboxUnavailable ||
                    status == SmtpStatusCode.TransactionFailed)
                {
                    // a new message!
                }
                else
                {
                    // TODO: Log other uncaught recipient failures
                }
            }
            else
            {
                // TODO: Log all other failure reasons
            }
        }

        client.Dispose();
        message.Dispose();
    }

As you can see I'm attempting to catch some recipients failures. If I find such an exception I want to try and resend the email.

I'm trying to work out how to resend the email safely. I'm thinking to create a new SmtpClient rather than reuse the existing one, but to be honest, I'm fairly new to .net and I'm not so sure of the implications.

Any advice would be appreciated.

dotnetnoob
  • 10,783
  • 20
  • 57
  • 103

1 Answers1

2

Sending email asynchronously without delaying response back to the client(UI) requires a Backgroundworker in .Net. I implemented this on my site and will share the class source code with you.

using System;
using System.Collections.Generic;
using System.Web;
using System.ComponentModel;    //Background worker namespace
using System.Net.Mail;


/// <summary>
/// Summary description for ClassName
/// </summary>
/// 

public class postmail
{
    BackgroundWorker bw = new BackgroundWorker();
    string email1, subject1, message1, failedemails;
    public postmail(string email, string subject, string message)
    {
            bw.WorkerReportsProgress = false;
            bw.WorkerSupportsCancellation = false;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            email1 = email;
            subject1 = subject;
            message1 = message;
    }

    public postmail()
    {
        // TODO: Complete member initialization
    }

    public void startsending() {
       bw.RunWorkerAsync();
       HttpContext.Current.Response.Buffer = true;
       HttpContext.Current.Response.Flush();  // send all buffered output to client
       HttpContext.Current.Response.End();
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
       var finalemail = email1.Split(new[] { ',' }, StringSplitOptions.None);
//loop through the email addresses and send individually
       for (int c = 0; c < finalemail.Length; c++) { 
           try
           {

               MailMessage mailMessage = new MailMessage();

               // Sender Address
               mailMessage.From = new MailAddress("emailaddress");

               // Recepient Address
               mailMessage.To.Add(finalemail[c].ToString());

               // Subject 
               mailMessage.Subject = subject1.ToString();

               // Body
               mailMessage.Body = message1.ToString();

               // format of mail message
               mailMessage.IsBodyHtml = true;

               // new instance of Smtpclient
               SmtpClient mailSmtpClient = new SmtpClient("mail server");
               //mailSmtpClient.EnableSsl = true;
               mailSmtpClient.Credentials = new System.Net.NetworkCredential("emailaddress", "password");
               // mail sent
               Object userState = mailMessage;
               mailSmtpClient.SendAsync(mailMessage, userState);

           }
           catch (Exception exc)
           {
            //fix for you
            var ext = exc.ToString(); //catch exception for failed message
            failedemails = failedemails + finalemail[c] + ","; //create a string of failed emails

           }       
       }

    }
    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    { 
              //called when the background process is done working
             if(failedemails != null){
                postmail(failedemails, subject1, message1); //resend the failed email
                startsending();
             }
    }
}

Your concept might not be exact like mine but the key methods are: Create an event handlers for the BackgroundWorker.

BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = false;
            bw.WorkerSupportsCancellation = false;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

bw.RunWorkerAsync();  

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
           try
           {
               //Send your mail

           }
           catch (Exception exc)
           {
               //Catch exception here and call the resend method
           }       
       }

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{ 
    //do something after completion
}

The fix i made for you was to build a string of all failed addresses, then resend them after the backgroundworker is done working. cheers!!

Ifeanyi Chukwu
  • 3,187
  • 3
  • 28
  • 32
  • If the failed mails keep failing.........the code will run infinitely. I suggest you create a boolean variable to check is resend is made, then terminate a second resend. – Ifeanyi Chukwu May 23 '13 at 17:31