Message Dispatcher





4.00/5 (1 vote)
Send e-mails asynchronously

Introduction
While programming various WEB applications, I have many times come across the need to send a message to interested users. For example, when a customer purchases a good from my e-shop, I want to send him an e-mail with the order details.
The piece of code that I am publishing here helps me out with this task as follows:
-
It is a DLL that offers me an API to send an e-mail.
-
Delivery is asynchronous. Hence, the application returns immediately and the actual delivery of the e-mail takes place later on. This has serious advantages over a synchronous delivery. Such as:
-
E-mail delivery may take some time, since it requires connection to SMTP server. With asynchronous delivery, the user does not perceive this delay.
-
SMTP server might be down and not responding to e-mail delivery. With asynchronous communication, I can build a nice retry mechanism.
-
Using the Code
In order to use it in your programs, you need to take care of the following:
-
Prepare your database. You need a Microsoft SQL Database. This is used to hold the messages that are queued for delivery. Note that in the folder
database
ofMessageDispatcherDAL
project, you will find the script namedcreate_and_initialize_tables.sql
that you can use to create and initialize the tables. IMPORTANT: The script DOES NOT create the database neither the login to access it. You have to do that. This is done, because it assumes that the whole set of the necessary tables would be most probably live inside a bigger database, designed to serve the needs of the application that would host the Message Dispatcher. What does the script do?-
Creates the table
Messages
. It holds the messages that you want to be delivered. -
Creates the table
MessageTypes
. Currently onlyemail
is really supported. But in the future, I may introduce the features to supportsms
too. You may find the valuesms
in the table, but this is not supported yet. -
Creates the table
MessageStatuses
. It contains the values of the statuses of the messages. The supported statuses are:-
NEW: Non-final Status. This is the status of a message that has just been put in the queue.
-
SENT: Final Status. This is the status of a message that has been successfully sent out.
-
FAILED: Non-Final Status. This is the status of a message that has not been sent out, due to some error. However, this is not a final status.
MessageDispatcher
will retry the delivery. -
ERROR: Final Status. This is a final status that indicates that the message has failed to be delivered, even if
MessageDispatcher
has tried more than once.
-
-
Creates the table
MessageBodyTypes
. This is a lookup table that contains two values:-
plain
-
html
If you are delivering an e-mail that contains HTML content, then you need to use
html
. If not, but just plain text, you need to useplain
. Note that if you choosehtml
then both plain text and HTML versions are combined in the same message. -
-
Schema: The schema in which all objects are created is
dbo
. If you want to change the default schema name, you need to:-
Edit
MessageDispatcherDAL.edmx
file in projectMessageDispatcherDAL
and change theSchema
entries to have the value you want, when now they have the valuedbo
. -
Also, in the same file, change the value of
DefaultDatabaseSchema
fromdbo
to whatever you want. -
Save and rebuild project
MessageDispatcherDAL
.
-
-
-
Install the Message Dispatcher Windows Service. Messages are being processed asynchronously with the help of a Windows Service. So, you need to install it. These are the instructions:
-
Project
MessageDispatcherWindowsServiceSetup
creates the setup.exe that you can use to install the service.OR
-
You can run the setup.exe that exists inside the zip MessageDispatcherWindowsServiceInstaller.zip that you can download from the top of the article.
Note that the installer installs the windows service and sets its Startup Type to be
Manual
. After the installation on your production server, change this toAutomatic
, so that whenever your server starts up, this service is started up automatically too. -
-
Configure Message Dispatcher Windows Service. Message Dispatcher windows service needs to know:
-
How to connect to the database to find out the messages that need to be processed.
-
How to connect to the SMTP Server in order to send the e-mails.
Configuration of the Message Dispatcher Windows Service is done by setting appropriately the values in the configuration file with name MessageDispatcherWindowsService.exe.config that resides in the folder where the service has been installed.
-
Configure database connection: Set the appropriate connection string with name
MessageDispatcherDALContainer
. An example is given below:<connectionStrings> <add name="MessageDispatcherDALContainer" connectionString="metadata=res://*/MessageDispatcherDAL.csdl| res://*/MessageDispatcherDAL.ssdl|res://*/MessageDispatcherDAL.msl; provider=System.Data.SqlClient; provider connection string="Data Source=MYSQLSERVER,50708\SQLEXPRESS; Initial Catalog=my_db;Persist Security Info=True;User ID=my_db; Password=my_db;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/> </connectionStrings>
-
SMTP Connection settings: In the same file, MessageDispatcherWindowsService.exe.config sets the following values appropriately, as in the example:
<appSettings> <add key="MessageDispatcherWindowsService.Smtp.Server" value="mail.foo.com"/> <add key="MessageDispatcherWindowsService.Smtp.Username" value="user@foo.com"/> <add key="MessageDispatcherWindowsService.Smtp.Password" value="password"/> </appSettings>
If your SMTP server does not require authentication, then set an empty string as value for both
MessageDispatcherWindowsService.Smtp.Username
andMessageDispatcherWindowsService.Smtp.Password
. -
Other minor service configuration settings:
- Sleep Between Processing: The seconds between processing messages. Windows service sleeps this number of seconds before checking again for new messages.
<appSettings> <add key="MessageDispatcherWindowsService.MainThreadSleepSeconds" value="3"/> </appSettings>
- Maximum number of failures before error: For each message that fails to be delivered, the service will retry that maximum number of times. If it fails all the times, the status of the message becomes ERROR.
<appSettings> <add key="MessageDispatcherWindowsService. MaximumNumberOfFailuresBeforeError" value="3"/> </appSettings>
- Timeout Between Retries In Minutes: For each message that fails delivery, the next retry will be later than this amount of minutes.
<appSettings> <add key="MessageDispatcherWindowsService. TimeoutBetweenRetriesInMinutes" value="3"/> </appSettings>
- Sleep Between Processing: The seconds between processing messages. Windows service sleeps this number of seconds before checking again for new messages.
-
-
Integrate in your Code. You need to use the
MessageDispatcher
API in your project in order to be able to send messages from your project. Follow the next instructions alongside theMessageDispatcherWindowsConsoleDemo
project:-
Reference MessageDispatcherDAL.dll in your project.
-
Create a database connection configuration string. This is necessary so that
MessageDispatcherDAL
knows where is the persistence storage of the message queues.For example, you can configure that in your app.config file (
<configuration>
section), if you have a Windows Console Application, as follows:<connectionStrings> <add name="MessageDispatcherDALContainer" connectionString="metadata=res://*/MessageDispatcherDAL.csdl| res://*/MessageDispatcherDAL.ssdl|res://*/MessageDispatcherDAL.msl; provider=System.Data.SqlClient; provider connection string="Data Source=MYSQLSERVER,50708\SQLEXPRESS; Initial Catalog=my_db;Persist Security Info=True;User ID=my_db; Password=my_db;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/> </connectionStrings>
Make sure you set correctly the server host name, the server port, the initial catalog, the user id and the password.
-
Create a message using the
Message.CreateEmailMessage(...)
method, as in the following example:// sender: no_reply@foo.com // receivers: customer1@gmail.com;customer2@yahoo.gr // ccReceivers: null // bccReceivers: null // Plain Text Example (last parameter is 'false') Message.CreateEmailMessage(no_reply@foo.com, "customer1@gmail.com;customer2@yahoo.gr", null, null, "Your Order Details", "Order ID: 5, Date of Purchase: 25-Nov-2011, Amount: 29.00 Euro", false);
This will create a new entry in the table
Messages
and on statusNEW
.Message Dispatcher Windows Service
will take care from there. -
Catch exception. Don't forget to wrap
Message.CreateEmailMessage(....)
in atry { ... } catch (...) {...}
block. Otherwise, make sure youcatch
any exception that this method might throw. You do not want your application to crash just because a message cannot be saved. Here is another example of using this method to send HTML message, wrapped tocatch
exceptions:try { Message.CreateEmailMessage(no_reply@foo.com, "customer1@gmail.com;customer2@yahoo.gr", null, null, "Your Order Details", "<html><head></head><body><b>Order ID:</b> 5<br /> <b>Date of Purchase:</b> 25-Nov-2011<br /><b>Amount:</b> 29.00 Euro<body></body></html>", true); } catch (EntityException ex) { System.Console.WriteLine("Cannot create message: " + ex.Message); }
-
Summary
I believe it is quite easy for you to send your e-mails asynchronously, using this DLL and Windows Service.
- Install the Windows Service
- Configure Windows Service
- Integrate in your code
Your comments are welcome and thanks for reading this far.
History
- 27th November, 2011: Initial post