Better email handling

Topics: General, Release notes
Sep 27, 2011 at 5:46 PM

So, a new package has seen the light. At least the outline of it, since there is still much to do. But the idea is quite simple.

 

Never loose any emails you're sending again. Ever!

 

So how do we do that? With email queues. This way your emails will be stored if the network is down or anything else unexpected happens. You will also have a full log of all mails being sent, so no more wondering of why the email is not showing up and where it might have gone. Best of all, you can have several queues with different setting. you might have different mailservers depending on the feature on your site - no problems. All the settings you would normally set in web.config can be configured directly from the console now.

You want to debug your mail functionality? No problem, any queue can be paused without effecting the live site and you can now see the mails being sent and inspect its content (at least thats the goal :)). When you resume the queue again, the emails will automatically be sent. You will also be able to delete emails in the queue if it contains a recipient your mailserver won't relay to or it got stucked for some other reason.

Email handling as it should be

Install it as a local package by downloading newest checkin here http://compositec1contrib.codeplex.com/SourceControl/list/changesets and browse for Email\Package\package.zip. It is still in its very early stage, but you're able to create queues with all its necessary settings and pause and resume them. Sending email is done through the EmailFacade class like this. Create a MailMessage object as usual, and give the name of your queue as argument for the SendMessage method. The message will now be queued and depending on if the queue is paused or not the message will be sent within a few seconds.

var message = new MailMessage()
{
   From = new MailAddress("info@acto.dk"),
   Subject = "Test mail"
};
        
message.To.Add(new MailAddress("poe@acto.dk"));

EmailFacade.SendMessage("default", message);

Warning

There is not much error handling on the thread sending emails yet, so if the queue settings for any reasons are invalid your site will go down with a bang. So only use this on a test site, but please come with your comments. Especially the good ones so i can keep the motivation for spending more evening and weekend hours on this :)

Coordinator
Sep 27, 2011 at 6:46 PM

Hi @burningice 

Looks cool, I'm gonna use it on www.composite.net. I have a few suggestions though.

The sending loop should check for "_running" between message sending. Otherwise if you have 10000 emails, the site will hang for half a minute while restarting.

Also you have the following sequence:

1) email send

2) message removed from the queue

It should be more like

1) email status -> sending

2) sending an email

3) setting email status to "send" (or deleting from the queue)

this was you don't have the situation when the same email is send twice (or multiple times in the case email server is sending email but returns an error)

The code would look like: 

 

private volatile bool _running;

...

using (var smtpClient = getClient(queue))
{
      foreach (var message in messages)
      {
	    if(!_running) return;

            var mailMessage = EmailFacade.GetMessage(message);


            Log.LogInformation("Mail message", "Sent mail message " + mailMessage.Subject + " from queue " + queue.Name);

	        try {}
		catch
		{
 		    // Executing code in "catch" section so the code won't be interrupted by ThreadAbortException on AppDomain_Unload event
            	    data.SetStatus(MailStatus.Sending);
	            smtpClient.Send(mailMessage);
	            data.SetStatus(MailStatus.Send);        //data.Delete(message);
  	        }  
      }
}

Sep 27, 2011 at 7:05 PM
Edited Sep 27, 2011 at 7:06 PM

I haven't made any status indication on each message yet, but that is definitively in as the next thing. Also being able to keep the sent messages and not automatically delete them and such things.

I've added some error handling and the check for _running as you suggested which makes sense. New code and package (0.3.1) checked in,