Sending notifications to the end users (email, sms, etc)

Author: Eugeniy Marilev
Tags: PHP Linux
Date of publication: 2014-05-07 10:23:09

What is the crucial problem with delivering the notifications? In my opinion the features of a simple, flexible and stable notification system are:

  • The system must provide different types of notifications and a variety of delivery mechanisms which we call channels (sms, email, etc). It must be simple to add a new channel to the system.
  • Activating or deactivating any channel must be easily customized.
  • It’s important to have detailed log of where and when notifications are delivered.
  • There must be background notifications. For example, I have posted a photo to a social network and each of my hundred offline friends must receive a notification about it. I don’t want to wait for all the notifications to be sent. I want to keep on using web-interface.
  • The system must include scheduling. Once a month, once a week, daily notifications, etc.
  • End user must be able to unsubscribe from a specific notification or from all of them.
  • Off course we prefer to deliver a notification as soon as possible, but if we can’t, there must be a tool for administrating the priorities. In case of a notification has not been delivered, the system must send it later if it’s needed.

How is delivery of notifications usually made?

Most frequently no one takes into consideration the problems mentioned above while developing a web site. But if you really care about how much people like the way your service works, you must notice them.

You can often meet the following construction in the web sites based on cms, various engines and frameworks:

  • mail($to, $subject, $body, ….)
  • MySuperEmailHelper::sendMail($to, $subject, $body, ….)
  • require_once 'SomeSMSServiceAPI.php';  $api = new SomeSMSServiceAPI(...); $api->send($to, $message, …)

Of course, it’s nice, because it works fast… But what if next day you will need to send notifications not only to e-mails, but also by sms? Would you find and replace the code all over the project or would you move the code of sending to the separate helper? And what if content may differ in different channels? Now that’s a problem…

In this article I’m going to show a simple to understand and flexible model of delivery that is designed to remove all this imperfections. You’re going to like it, because it’s simple. But previous to the system please read some useful information.

Why do I think that built-in delivery module is better than using the online services?

I made the following conclusions about notification web-services.

Positive sides:

  1. You don’t have to write code. It costs more but demands less effort.
  2. You can edit patterns of the notifications within an admin part of a web-service.

Negative sides:

  1. There are periodic payments or even payments for traffic.
  2. History of notifications contains only general statistics about subscribers and notifications count. There is no detailed log.
  3. It’s hard to find a service that provides delivery of notifications through the different channels, for example to email and by sms.
  4. Every time, when a user subscribes, http request must be sent to the service. This makes a delay during the registration on your web site.
  5. Database of delivering service and data base of your web application are different, so the problems of synchronization appear. Let’s imagine that a user has changed his email on your web-site, I’m sure that he expects that notifications will be delivered to the new one...
  6. You don’t have any option to improve the performance of the system, because you can’t add one or two servers to it.
  7. There is no flexible tool for administrating the priorities. For example there are three types of users on your application: free, business and premium. The goal is to satisfy premium users, business users are less important and when it’s done for the premium and business users the rest time may be spent on the free users (this isn’t a big problem if a free user won’t get some notification). But for the notification service they all are just addressees.
  8. Finally it isn’t productive to use a web-service for “just now” notifications, which are commonly used for confirmation emails. If you need to change something, patterns of notifications and programming code are edited separately within a web-service admin part and in your application. In my opinion this is kind of perverse.

Base entities of delivery cycle

There two general types of notifications:

  1. Notification on some events.
  2. Scheduled notifications.

The second one is simpler, because there is no strict pattern for it. Notifications are independent of system events, so the pattern defines the content itself. But for the first one everything is much more complicated. Let me introduce an entity “Notification” that may have a various structure. When an event occurs, the system saves its content to the data base. This is the first step of the delivery cycle.

The second part of the delivery cycle is directly the delivery. “Delivery” is associated to a specific “Notification”. “Delivery” contains information about recipients’ addresses accordingly to the notification channels. The client may have an email and a phone number, so an instance of “Delivery” includes an sms that has to be sent to the phone number xxx and an email to the xxx@xxx.xxx address.

An entity that defines a type of notification is called “DeliveryChannel”. When an instance of “Delivery” has been created it has a “recipients” property. An item in a set of recipients is a pair of elements – a type of notification (“DeliveryChannel”) and an address according to the channel. Sending a content is hidden in a specific implementation of “DeliveryChannel”, i.e. we call functions mail(), sendSMS() and others within implementation of a specific notification channel.

Let’s go back to the “Notification”. Now, when all the entities are defined it’s easier to understand why a topic and content of a notification are generated accordingly to the channel in the class of “Notification”. For the scheduled notifications there is NotificationStatic class, which has static properties Subject and Content.

Delivery cycle at work

In our system particular attention has been given to the priorities of delivery, delaying and scheduling notifications. The amount of the notifications that are being sent in a time is limited, because we don’t want to overload our servers.

We have developed a script that works as a daemon and retrieves from a data base the “Deliveries”, that haven’t been sent yet. Massive of deliveries is sorted by priority. About 50 – 100 records are selected and tagged so they won’t get into the next iteration.

Would you like to try it? You can download an extension to yii

I hope that everything described above was clear. There’s good news, the system is opensource and available for download on yiiframework.com in extensions section. Or click here.

Advantages and disadvantages

This approach allows us to work with notifications more easily and flexible, but there are some disadvantages:

  1. Additional abstraction leads to the lot of additional function calls and variables, so the system works slower than an individual solution.
  2. DBMS is needed.
  3. You need your own mail server or sms gateway.

Distributed notification system

In this section I will tell you about horizontal scaling of the system, that easily resolves the problem with a server overloading.

There is a cool and what is more important multipurpose solution for the distributing the queues. This technology is called AMQP. You can read more about it here. There is a realization called RabbitMG on the Erlang language for *nix and windows systems. Erlang is still open and free solution.

This service provides a queue creation and putting the messages in there. You can create queues inside of your web-application and put the information about what and where must be sent without actually sending it. Services that can be placed on the other servers (or a daemon *nix) read the messages from a queue according to the schedule.

That means you can have 4 servers for the e-mail channel and 2 for the sms. On the main web-server in the “DeliveryChannel” implementation a message is putted into queue “mail” instead of being sent. Similarly for the sms channel there must be a queue “sms”. Then the daemon service on the sms gateways gets the messages from the “sms” queue and sends them (similary for the mail servers). Thus, the multithreaded sending has been achieved.

Also we need to save a delivery time in a log. This can be done when a notification has been added to the RabbitMQ. I choose to create an additional global queue that contains information about time, content and addressees of the notifications. The main server reads the information from this queue and save it to the database.

Of course there are distributed mail servers with balancer, but it is much more difficult to administrate them.

Well, if you think the information is useful please like

Article comments
Comments:
No results found.
Only logged users can leave comments.