A Newsletter Sending System Code Challenge

Brian Emory
Brian Emory | Web Developer
6 min readAug 11, 2017
A 1,000 email test run

Completing it taught me a lot

I was tasked with a code challenge to create an Elixir/Phoenix app that would be a newsletter sending system. The requirements were simple and I had 48 hours to complete it. I lost a bit of time on the first day which caused me to cut some corners and not use TDD (tsk tsk). I had a deadline and would not miss it.

It was a great opportunity to build another app with Elixir and Phoenix. I learned more about changesets while trying to update users in iex, dove deeper into writing tests, and found that I need to learn a lot more about async and parallel tasks in Elixir. It is always great to learn more while doing.

If you have any suggestions of how I can improve my code, please let me know!

Code challenge requirements

What it should do:

  • A not logged-in user will see a form requesting their email, which will allow them to subscribe to the newsletter.
  • The user of the system (i.e. author of the newsletter) can write a newsletter and send it to all the subscribers (by email). Keep in mind that in a real-life scenario, there may be 10–100k subscribers, so sending emails in a synchronous way (e.g. calling a send_mail(email, body) function while looping all the subscribers) is not a valid option.

Bonus points if:

  • Subscription is confirmed by sending an email with a ‘Confirm your subscription’ link
  • A newsletter can be scheduled to be sent at any time in the future (usually, newsletters are sent in a biweekly or monthly schedule)
  • Automated testing is included

Although it was not specified, I ignored how easy it would be to capture email addresses and send a newsletter through any of the number of systems available. SendGrid is an example of one and I utilized their service for sending emails from within the app. The capturing of emails and sending of the newsletter was all handled in the app.

You can see the code on my GitHub. Against what I should have done, I skipped adding tests until after. I had a deadline and needed to get it done. I did not know enough of testing in Elixir and felt learning that and writing the app in my 48 hours would have been a problem. Now that I am more familiar with Elixir and writing its test, I can feel confident that writing tests first would not slow me down. After all, TDD is my preferred way to code.

Signing up for the newsletter

The first task was for a visitor to the site to see a form requesting their email address. It would have been easy to create a simple form to grab the email address and add it to the database. However, I was looking ahead to being able to send an email to confirm the subscription. It seemed to me the easiest way would be to use an authentication system.

I decided on Coherence as it had the email confirmation system that I wanted. I figured it would be easy enough to tweak it so instead of needing a name, email, and password to sign up, you would only need an email. It was not easy. Well, it ultimately was but it took me a long time to get to that point.

When I first ran the Coherence install, I ended up with a user module and migration that looked like this:

The problem I ran into that took up so much of my time, was the eliminating of a password from being needed. I tried removing it from the migration, following the validate_coherence(params) function and removing any password references it led to, but everything I did kept kicking back one error or another. I could not seem to track down where the password was getting set.

After spending way too much time on it, I decided to keep in the password field and much like the name field I kept, set a default value in the migration and schema. This of course also failed because of some of the same reasons as above. There were things Coherence was doing that I did not quite understand.

I eventually decided that I needed to get moving on to the next step. I started passing in a password using a hidden form field as a temporary measure. A terrible approach but sufficient for now until I get the rest of the app finished. Make things work then make things better.

Using a hidden field for the password was eventually removed when I discovered a solution while working on changing an admin’s password in iex. It turned out by simply removing validate_coherence(params) from the user.ex changeset/2, passwords would default to nil, and a user would never be able to sign in without having their password changed manually.

Email confirmations

One of the bonus points was an email being sent out to confirm a subscription. Coherence has this baked in and was pretty easy to follow their docs and implement. Putting my app on Heroku allows for a free SendGrid account that allows for 12,000 sent emails a month. I will later make use of a lot of those to test things out. Coherence had instructions for setting up a SendGrid adapter and making sure confirmation emails were going out.

Sending out a newsletter

Now, I need to have an admin be able to send out a newsletter to all the subscribers. One problem here is all my users have the same fake password that is passed in by the hidden form field. Anyone that would have inspected the source of the page could see it and use the password to log in and send out emails. That is not something we want.

First step I took was adding a role to all of the users. It would default to subscriber and the admin would have to be changed by using iex to get into the database. Not something you would want in a production app but good enough for the purpose of this code challenge. I was able to add a role and set the default easily enough by tweaking the migration and user.ex to add the extra field.

I signed up for an account with the address I would use as my admin and clicked the email confirmation link to confirm the account. I used iex to update the role to admin and created a page only accessible to those whose role was admin. This would bounce any user who managed to get a hold of their hidden input field password.

I created a form that had a subject and body field. It posted to my newsletter_controller :create and off my emails went! This process is currently way too slow, 5,000 emails took 5 seconds to process from the time I clicked send to the time I got the flash message telling me it was successful. This is an area for large improvements. There is this great post I saw called “Reducing Elixir Backend Time from 120ms to 20ms With Parallelization” which really shows how great Elixir can be.

I mirrored my newsletter_email.ex after Coherence’s user_email.ex. This is essentially the same process used to send the confirmation emails. It takes the user and gets their name and email, and grabs the subject and body from the params.

Things to improve

The app is not perfect by any means. I would have liked to have the newsletter be able to be scheduled as per one of the bonus points. I also would have liked to have a few more tests for things like invalid data with the signups and log ins.

As I mentioned before, I really want to dive deeper into speeding up the sending of the newsletter. Receiving the confirmation flash message should be basically instant after I click send. No reason it should take five seconds.

I look forward to learning more about it.

Follow me on Twitter @thebrianemory. Follow me here, click the hands below to show some appreciation, leave a comment, and get in touch!

--

--

Brian Emory
Brian Emory | Web Developer

Backend Software Engineer (Ruby/Elixir). Giraffe-like qualities. I enjoy video games, bad movies, hard ciders, and pizza.