1

I have a site I manage for a client and they wanted to be able to send out emails to all of their membership. I contacted the host and they suggested writing it in a way that it sends out in batches of 50 or less every minute so the mail server doesn't get overloaded.

That sounds great but the only way I could think of to do this without causing the administrator to have to sit on a page while it sends emails and reloads between each batch was to have a page call an ashx handler which fired up a thread to do the work and the thread is set to sleep after each batch for 60 seconds.

When I run the code from my machine it works fine and completes the entire list of emails. When I run it from the web host, which I don't have access to aside from ftp, it nearly completes but doesn't. Then if I try to hit the ashx page again to finish any that weren't sent, it doesn't do anything. It's like the thread causes something to lock up maybe and keeps additional threads from running.

Here's the code I'm using and I've never used threading before... so, does anyone know why it might be doing this and how to make it work correctly? Do I need to specifically kill the thread after I'm done? If so, how? Thanks.

public void ProcessRequest(HttpContext context)
    {

        if (context.Request.QueryString["id"].IsValid<int>())
        {
            campaignId = context.Request.QueryString["id"].To<int>();
            var t = new Thread(new ThreadStart(SendEmails))
                        {
                            Priority = ThreadPriority.Lowest
                        };
            t.Start();
        }
    }

    private void SendEmails()
    {
        int currentCount = 0;
        BroadcastEmailCampaign campaign = EmailController.GetCampaign(campaignId, false);
        List<Member> memberlist = EmailController.GetEmailList(campaign.CampaignId);

        var message = new MailMessage
                          {
                              Body = campaign.Body,
                              From = new MailAddress(campaign.SentBy),
                              IsBodyHtml = true,
                              Subject = campaign.Subject,
                              BodyEncoding = Encoding.UTF8
                          };

        //add attachment
        if (!string.IsNullOrEmpty(campaign.Attachment) && File.Exists(campaign.Attachment))
        {
            var attachment = new Attachment(campaign.Attachment);
            EmailAttachmentType.SetContentProperites(campaign.Attachment, ref attachment);
            message.Attachments.Add(attachment);
        }

        if (memberlist.Count <= 0)
        {
            return;
        }

        bool sendingComplete = false;
        EmailController.SetCampaignSendingStatus(true, campaign.CampaignId);

        while (sendingComplete == false)
        {
            message.Bcc.Clear();
            message.To.Clear();

            message.To.Add(new MailAddress(dummyEmailAddress));

            List<Member> emailsToSend = memberlist.Skip(currentCount).Take(takeCount).ToList();

            if (emailsToSend.Count <= 0)
            {
                sendingComplete = true;
                EmailController.LogEmailCampaignResult(campaign);
                EmailController.SetCampaignSendingStatus(false, campaign.CampaignId);

            }

            if (!sendingComplete)
            {
                foreach (Member email in emailsToSend)
                {
                    message.Bcc.Add(new MailAddress(email.Email));
                    campaign.SentTo.Add(new BroadcastEmailCampaignSentTo
                                            {
                                                MemberId = email.MemberId,
                                                Email = email.Email,
                                                DateSent = DateTime.Now
                                            });
                }

                EmailController.SendEmail(message);
                EmailController.LogEmailsSent(emailsToSend, campaignId);

                currentCount += takeCount;

                Thread.Sleep(pauseTime);
            }
        }

    }

2 Answers 2

1

Since I read a lot of threading in ASP.NET and still have no real clue of the dos and donts, I usually solve tasks like you describe by a console application that runs as a Scheduled Task in Windows Task Scheduler every e.g. 5 minutes:

  1. In the ASP.NET page, I write all required information into a database table.
  2. The scheduler periodically polls the database table for new jobs (e.g. sending of an e-mail) and processes, then empties the database table that serves as a queue.

This enables my application to stay responsive and in addition I don't have to worry that an IISRESET or something like this would kill my background threads.

Sign up to request clarification or add additional context in comments.

Comments

0

t.IsBackground=true;

If that doesn't do it, I suggest using the ThreadPool with QueueUserWorkItem.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.