Our Tech Stack - boring tech, services not microservices, and no big cloud providers
September 22, 2023
At MailPace we’re focused on a building a simple, low cost service for people to send transactional emails. We’ve built our tech stack with that in mind, around three principles:
- Use boring tech - we use things we already know how to use, that have been proven before
- Separation of responsibility for our critical components - services, not microservices!
- Avoid the big three cloud providers (Google AWS Azure) - we specifically avoid cloud-native technologies (proprietary services that can only be run by someone else), and we like to stick to European providers/locations
We’ve ended up on a fairly stable tech stack, here it is:
App & API
This is what you hit when you send an email with app.mailpace.com/api/v1/send or look at your email dashboard at app.mailpace.com
Front end and API: Rails
We use Rails 7, with Turbo for the front end JavaScript / interactive parts. Rails is by far the simplest way to get a CRUD app up and running, and has proven itself well.
Yes we could rewrite our API in Rust and be a bit faster (and we might do that in future). But RoR is so easy to add new features, Ruby is a complete joy to write code in, and both Ruby and Rails are getting a lot of updates all the time (but not too many changes, looking at you JavaScript ecosystem).
Database: Postgres
Just use Postgres, seriously.
Background Jobs: ActiveJob with Sidekiq and Redis
Sidekiq runs a job for all our outbound emails and many other background jobs, using Redis to store the details and state of the job. Again this is proven, easy to use tech.
Hosting: Clever Cloud
All of this is hosted on Clever Cloud in Paris, with GitHub based deploys from master branch, via a Dockerfile.
This means we don’t handle any operations infra, so if our Rails app needs to scale we let Clever Cloud handle all the load balancing, horizontal and vertical scaling etc.
The downside of this is a lack of tuning for performance or quality of life improvements (e.g. our deployments take longer than we’d like, maintaining the database requires support from them, we’re reliant on their setup of VMs etc.) but overall a worthy trade off.
SMTP Servers
Naturally, we run several SMTP servers for sending emails, receiving emails, and for our SMTP gateway at smtp.mailpace.com
.
Inbound SMTP & SMTP Gateway: JavaScript
We have our own custom written JavaScript SMTP Servers, which are very lightweight and can easily scale to thousands of emails/second. We use JavaScript because a) we know it well and b) node.js is reasonably fast / lightweight for handling async processes.
These are hosted on fly.io, and use fly deploy
for deployments, based on a Dockerfile. The Fly VMs are really lightweight and deployments are super fast, as well as fully managed.
Outbound SMTP: ZoneMTA (JavaScript)
We do like to send lots of emails, so here we chose JavaScript again as we found that ZoneMTA was by far the easiest Mail Transfer Agent (MTA) to write plugins for and configure. This means we can pull DKIM keys in real time, run spam checks, update our database on emails being sent/bounced etc.
Our outbound emails are hosted on Ubuntu VMs from Freethought with deployments based on Capistrano. These rarely change, so we’re happy with simple, old school server management for these servers.
The bits in between: HTTP Services
We use HTTP RPC calls to send/receive data between services. This gives us a bit of freedom and resiliency between components. We know HTTP well and it’s trivial to work with in any language.
We operate Redis caches between HTTP services for speed/resilience, here’s how we do that.
File Storage
Backups: Clever Cloud and AWS S3
We have backups at regular schedules from Clever Cloud and also an additional backup to AWS S3, using the backup gem.
And we have tested our restore process :)
Attachment storage: Clever Cloud Cellar
Cellar is an S3 equivalent from Clever Cloud. We wrote about how we moved from Postgres to Cellar for attachments here.
Static Sites
This blog: Gatsby
You’re probably reading this on Gatsby , which is (was?) a react-based static site generator. I think it’s now some kind of JS framework. It works well, but actually is a complete pain to set up and always has some kind of dependency issue whenever we try to run it locally. This is one area where we think there are faster to set up/easier to maintain alternatives for a blog, but it works and we dare not touch it for fear of it breaking.
All the blog posts are written in markdown so we could easily switch to something else if we wanted to.
Docs: Docusaurus
Our documentation pages are super important, we’re using a project that came out of facebook, Docusaurus, it’s very easy to work with and is also built around markdown files.
We have Algolia for search baked in, straightforward to setup and works well.
MailPace.com - HTML Modules + TailwindCSS
This is probably the simplest part - we started with HTML, with a sprinkle of JavaScript. Then added HTML Modules using npm scripts and added TailwindCSS. It’s perfect and easy to maintain.
Hosting: Netlify
We use Netlify to host these static sites. Very easy to set up, deploy straight from github. There are plenty of options here, e.g. github pages, vercel etc.
Automation
We have a separate VM for running Cron jobs. We use it to also send out emails to ourselves regularly using the greatest transactional email API available, our very own mailpace.com, and we previously wrote about why sending emails is a great way to monitor your app.
We automate our SMTP cert renewal (surprisingly complex) with fly.io machines, here’s how we did that.
Other Services
- Paddle for payments and checkout - they act as a merchant of record, and this means we don’t have to worry about collecting taxes, VAT, or any of that stuff
- Plausible for user analytics - only on the static sites, not on the app, we don’t track that anywhere outside of server logs and database changes
- AppSignal for Error and Performance monitoring - they offer a lot of pieces
- VSCode (with Github Copilot) for writing code
- Masto.host for Mastodon (Social media) - essential given Twitter’s current state
- Letsencrypt for SSL Certificates
- Cloudflare for DNS and CDN on static sites
- Github for git hosting
- Trello for task management
- Tutanota and Hey for “normal” emails
Phew! I think that’s everything. I guess it’s not as boring/simple as I thought before I started writing this!
Oh I forgot, we use MailPace for transactional emails, naturally. And we don’t send marketing emails in case you were wondering what we use for that!
By Paul, founder of MailPace. Follow our journey on Mastodon and Twitter, and sign up to our Product Newsletter.