Provide up-to-date information in an email sent hours ago with Elixir/Phoenix

JayPads are build for live and asynchronous collaboration and communication so it’s vital you stay up-to-date about what’s happening.

One corner stone of JayPads is the discussion feature which works a lot like Slack or WhatsApp. The problem with these systems is nicely described here. In essence if everything is a notification nothing is.

We solved the problems described in his blog post in two ways. For one we provide a way to store relevant information in separation from the ever ongoing discussion. And on the other hand we handle notifications a bit differently. For a more comprehensive but less tech-heavy explanation of the Whys and Hows behind this read this blog post by my colleague Hanke Wickhorst.

We send out notification emails to the users that are not online at the moment but we do not want to spam them with every single thing happening. Instead we send one email with the latest information available at the time of sending and then hold back any new information and do not send any additional emails. That is until the user visits the JayPad or opens the email.

Now the problem with that is when the user reads that one email hours later he only sees the information available at the time of sending.

We solved this by including a dynamic image which gets calculated at the time the user opens the email and presents the information of how many more new messages there are as of right now.

A typical JayPad notification email with one old message for context, the new message highlighted and an indicator how many more new messages there are.

In the email’s template there’s an <img> which’s src points to an API endpoint and all the relevant information (to calculate the number of how many more messages there are) is given via the path.

The controller is fairly simple as well. It takes the arguments of which language to show the message in, and the two parameters from which the number of additional messages can be derived. It then calls a GenServer which returns the bitstring representation of the wanted image. This is then returned as the response from the controller with the correct content type of “image/gif”. With this construct the image url stays the same but returns varying results depending on the state of the JayPad. The images are all pre-generated. We decided that 12 images per language (for now this is english and german) are a sufficient indicator for the user: An empty image (if nothing else has happend), images saying “… and 1 more message” up to “… and 10 more messages” and “… and 10+ more messages” for everything beyond that.

I did the module that returns the image bitstring as a supervised GenServer for a simple reason: I do not want to load the image file from disc every time it is requested. Instead I wanted to have it already available in memory at the time of request.

This is state. Hence GenServer.

The GenServer loads all the files into a Map on initialisation and serves it from there on request. What’s quite nice about a supervised GenServer is that when it crashes for some reason it automatically loads all the image data into memory again on restart of the GenServer. This init on restart is out-of-the-box default behaviour of Elixir’s supervision and comes in very handy for this particular use case.

We are constantly tweaking this mechanism to give our users the best non-annoying-but-stay-up-to-date notification experience. Any thoughts and ideas on the technology and methodology are welcome. Now go and plan your next big thing (with JayPads of course ;-)