At Abenity we send a LOT of email. Due to requirements we have around proprietary business rules, we had to roll our own system for managing lists, campaigns, and templates. We then coordinate this information with a third party service to actually send the email. The volume of emails we were sending was becoming a bottleneck; one of our team members devoted around 80% of his time solely to creating custom HTML email templates. We wanted to both free up his time and empower our marketing team to do this work without needing help from the development team, and we wanted to refactor a legacy system that grew organically over time (and had gotten a little gnarly in the process) into something that was easily understood and more maintainable. I was especially excited for this project because I like helping other teams at our company by building internal tools like this one, I enjoy cleaning up legacy code, and I enjoy working closely with the backend to figure out the best way to build complex features like this.
There were two main problems that needed solving with this update. Number one, we needed to create an admin for managing campaigns and understanding how it coordinated with the mailing service we were using to actually send the final email. This needed a whole new business “language” developed around it so that new hires could intuitively understand the system as well as someone who had worked with it for years. Number two, we needed a way for someone with no HTML experience to be able to create custom HTML emails.
The first step of this phase of the project was to build a modular system of HTML components that could be composed into a variety of HTML email layouts. I created a master responsive HTML email that included all of these base components, a sort of mini design system for all of our emails. It had to work across our testing suite of email clients (thanks Litmus!) without using media queries (thanks Gmail on Android!). Yes, it’s as gross and weird as it sounds to build responsive emails out of tables without media queries, but it’s also surprisingly doable with a bit of planning.
The next step was to create a way to both organize these components into templates and to allow our marketing team to enter content into these templates. I helped devise a system where each template has a corresponding set of JSON that says what content is required for that template. This JSON is then translated into a form by a Vue component for entering that content. Finally, there is a corresponding Blade template that reads the data created by the form and generates an HTML page. This is pulled into an iframe that is positioned by the form for an updated real time preview any time you save you work. The end result is being able to compose both templates and forms for powering the content in those templates.
Attention to Detail
I added warnings to let you know when there are unsaved changes and a prompt that alerts you if you try to leave the view (whether on purpose or accidentally) without saving. Some of these emails get pretty long also, so I have the iframe scroll to the section you’re editing and highlight it. As a last touch, I added a dropdown that allows you to select any of our clients and preview the email as that client to view any data driven customizations that would be made to the content. We even added the ability for the client to preview the email in one of our apps and approve it for their users before we send it!
The next piece of this project was creating the admin, part of an internal SPA built with VueJS, to organize the templates into coordinated campaigns that we can send to clients. We have a pretty unique set of rules that control this, so I don’t want to divulge too much, but this system was at a place where it was hard to explain to anyone new joining the team. It was a methodology that grew organically over many years as the business grew. The legacy system also did not report how the campaigns were synced with the third party system we use to send the emails, so it was hard to know quickly if you had run into a snag with the process.
The solution was to take a step back and assess how the pieces of the system fit together, and use this to create a shared language for the team to understand and communicate it to one another and to future hires. I sat down with the backend developer that was syncing this info with the our mailing service to hash out what to call everything. I then used the Breadboarding methodology to rapidly work through UI options until we were satisfied. Finally, I built out the system of Vue components to power all the forms and views for creating campaigns, including controls to generate campaign sets from information such as client geographical data.
We communicated the way the new system worked to our marketing team and trained them on how to use it. It was a really big success. Work that used to take days or weeks and required just about all of one of our team member’s time now only took a few hours. We put the power entirely in the hands of our marketing team by building tools to help them create specialized work without needing to involve the development team at all. We also helped to improve the overall process with better reporting and insight into the process of sending emails that was taking place. Empowering others to do their best work with something that I build is very satisfying for me, and this project is a prime example of that.