1

I'm trying to send confirmation mails to users periodically in ASP.NET.

To do this I polulate a queue with mails and check it every 30 seconds. Any confirmation emails in the queue at this time are sent and then cleared from the queue.

Does anyone know how to do this?

Here is my sending mail code

public static bool SendMail(string AdminMail,string AdminPassword,string subject,string toAddress, string content,DateTime SendTime)
        {
            toAddressListProperty.Enqueue(toAddress);

            if(date==null)
            {
                date = DateTime.Now.Second;
            }
            if (date-SendTime.Second > 120)
            {
                    var message = new MailMessage
                                      {
                                          From = new MailAddress(AdminMail)
                                      };

                    foreach (var toAddressl in toAddressListProperty)
                    {
                        message.To.Add(new MailAddress(toAddressl));
                    }

                    message.Subject = subject;
                    message.Body = content;
                    message.IsBodyHtml = true;
                    var smtp = new SmtpClient
                                   {
                                       Credentials = new System.Net.NetworkCredential(AdminMail, AdminPassword),
                                       Port = 587,
                                       Host = "smtp.gmail.com",
                                       EnableSsl = true
                                   };
                    smtp.Send(message);
                //date = SendTime;
                return true;
            }
            return false;
        }
Ryan Spears
  • 2,963
  • 2
  • 31
  • 39
Islam
  • 1,647
  • 6
  • 27
  • 40

4 Answers4

1

I have done this using a background thread. I did a little research, and I believe this is an ok approach. There are a few dangers, which this blog details.

The main thing is to ensure you never throw an exception from a background thread, as I believe that will cause the web process to restart. Also, incase the thread dies, I ensure it is running on every call.

I have been using this approach for a few months, and so far no issues.

Also I run it every 1 second, this minamizes the amount of time you might loose emails due to an app shutdown.

public class BackgroundSmtpService
{
    private ILog _log = LogManager.GetLogger(typeof(BackgroundSmtpService));
    private readonly SmtpService SmtpService;
    private static Thread _watchThread;
    private static List<Email> _emailToSend = new List<Email>();

    public BackgroundSmtpService(SmtpService smtpService)
    {
        SmtpService = smtpService;
    }

    public void Send(Email email)
    {
        lock (_emailToSend)
        {
            _emailToSend.Add(email);
        }
        EnsureRunning();
    }

    private void EnsureRunning()
    {
        if (_watchThread == null || !_watchThread.IsAlive)
        {
            lock (SmtpService)
            {
                if (_watchThread == null || !_watchThread.IsAlive)
                {
                    _watchThread = new Thread(ThreadStart);
                    _watchThread.Start();
                }
            }
        }
    }

    private void ThreadStart()
    {
        try
        {
            while (true)
            {
                Thread.Sleep(1000);
                try
                {
                    lock (_emailToSend)
                    {
                        var emails = _emailToSend;
                        _emailToSend = new List<Email>();
                        emails.AsParallel().ForAll(a=>SmtpService.Send(a));
                    }
                }
                catch (Exception e)
                {
                    _log.Error("Error during running send emails", e);
                }
            }
        }
        catch (Exception e)
        {
            _log.Error("Error during running send emails, outer", e);
        }
    }
}
Iain
  • 10,814
  • 3
  • 36
  • 31
1

You might want to consider using Quartz.net library. It have decent documentation and it's fairly easy to use.

0lukasz0
  • 3,155
  • 1
  • 24
  • 40
0

The biggest challenge you'll have with this is that any time your application pool recycles it will take a new request to kick stats your "timer". If you had an HTTP monitor application such as Pingdom to poll your server it shouldn't be a problem, but then again you could also just use a third party monitor tool to hit your a page on your site every N seconds that would send out the mail and issue a response.

I myself would use a Windows service to pull a queue from a database and send out messages that way.

Nick Bork
  • 4,831
  • 1
  • 24
  • 25
0

Easiest way is to create a VBScript that sends an HTTP GET request to http://localhost/SendConfirmationEmails.aspx

You'd start the VBScript in your global.asax Application_Start method.

The SendConfirmationEmails.aspx would act as a simple web service (you could use an ashx, or actual web service asmx if you wanted). It would only be accessible on the localhost so remote users wouldn't be able to spam it.

Using a windows service is probably the best practice method, but a simple VBScript will get the job done.

surl="http://localhost/SendConfirmationEmails.aspx"
set oxmlhttp=createobject("msxml2.xmlhttp")
with oxmlhttp
    .open "GET",surl,false
    .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    .send srequest
end with

You'd put the code above in a while wend loop with a Sleep to delay every 30 seconds...

Louis Ricci
  • 20,804
  • 5
  • 48
  • 62