Sending email asynchronously in ASP.NET C #

I was wondering if there is a way to send an asynchronous email in asp.net C #. I used the following code to send emails:

 if (checkObavijest.Checked)
            {
                List<hsp_Kupci_Newsletter_Result> lista = ServisnaKlasa.KupciNewsletter();
                for (int i = 0; i < lista.Count; i++)
                {
                    MailMessage mail = new MailMessage();

                    mail.From = new MailAddress("*******");
                    mail.To.Add(lista[i].Email);
                    mail.Subject = "Subject";
                    mail.SubjectEncoding = Encoding.UTF8;
                    mail.BodyEncoding = Encoding.UTF8;
                    mail.IsBodyHtml = true;
                    mail.Priority = MailPriority.High;
                    mail.Body = "Some message";
                    SmtpClient smtpClient = new SmtpClient();
                    Object state = mail;
                    smtpClient.Credentials = new NetworkCredential("****@gmail.com", "****");
                    smtpClient.Port = 587;
                    smtpClient.Host = "smtp.gmail.com";
                    smtpClient.EnableSsl = true;
                    smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted);
                    try
                    {
                        smtpClient.SendAsync(mail, state);
                    }
                    catch (Exception ex)
                    {

                    }
                }

 void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {

            MailMessage mail = e.UserState as MailMessage;

            if (!e.Cancelled && e.Error != null)
            {
                string poruka = "Emailovi poslani!";
                ClientScript.RegisterStartupScript(this.GetType(), "myalert", "alert('" + poruka + "');", true);
            }
        }

      

But when I check the option to send emails, the page loads as 40 seconds and then emails are sent 40 seconds later. As you can see, I am logging out 20-30 emails from my database. I thought this is the correct way to send emails asynchronously, but apparently it isn't ... How can I send email to another thread so that it doesn't affect the user who is using this page? Can anyone help me with this? Thank!

+3


source to share


2 answers


The reason is mentioned here in the MSDN documentation on SmtpClient.SendAsync

After calling SendAsync, you must wait for the entire email to be sent before trying to send another email using Send or SendAsync.

You can call SendAsync

using ThreadPool

by calling the wrapped method. This will give you a kind of fire-and-forget scenario.

Something like that:



public void SendViaThread(System.Net.Mail.MailMessage message) {
    try {
        System.Threading.ThreadPool.QueueUserWorkItem(SendViaAsync, message);
    } catch (Exception ex) {
        throw;
    }
}

private void SendViaAsync(object stateObject) {
    System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient();
    System.Net.Mail.MmailMessage message = (MmailMessage)stateObject;
    ...
    smtp.Credentials = new NetworkCredential("...");
    smtp.Port = 587;
    smtp.Host = "...";
    ...
    smtp.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted);
    ...
    smtp.Send(message);
}

      

And you would be named SendViaThread(mail)

in your code. So your loop now becomes:

for (int i = 0; i < lista.Count; i++) {
    MailMessage mail = new MailMessage();
    mail.From = new MailAddress("...");
    mail.To.Add(lista[i].Email);
    mail.Subject = "...";
    ...
    mail.Body = "...";
    SendViaThread(mail);
 }

      

0


source


If you don't want your main thread to wait, try throwing it in a Task.

Task.Factory.StartNew( () => {
  // do mail stuff here
});

      



Remember that every time you create a task, it spawns a new (or re-using) thread that your system did. If you shoot 30 emails, you have the potential to shoot a lot of threads (the system also has a programmable cap). Task.Factory.StartNew

is a very easy way to complete the fire and forget process.

http://msdn.microsoft.com/en-us/library/dd321439%28v=vs.110%29.aspx (in this example, the code also stores a collection Tasks

, which is nice if you want to manage them, but really you needs a bit Task.Factory.StartNew(()=>{

if you want to shoot and forget Just be careful because you don't want orphan threads to bind your memory usage.

0


source







All Articles