14
.
11
.
2023
25
.
02
.
2021
Ruby on Rails
Tutorial

How To Receive Emails With a Rails App in 2021

Michał Łęcicki
Ruby Developer

Table of content:

  1. Problem
  2. Solution 0: Rails Action Mailbox
  3. Solution 1: Third-party integration with Griddler
  4. Solution 2: IMAP protocol
  5. Solution 3: AWS SES
  6. Summary

Problem

Some time ago, we needed to implement a full email inbox feature in the Ruby on Rails application. It was supposed to have all the basic functionalities that regular email inboxes have: send and receive messages, collect them in threads, have a contact book, etc. While email sending is a relatively frequent feature among Rails applications (there are tons of different solutions around the web), receiving messages is not so popular. So, let’s take a look at possible ways of building an email receiver mechanism with Rails.

mailphoto

Solution 0: Rails Action Mailbox

Rails 6 release in 2019 changed the way of handling emails in Ruby on Rails applications by introducing the Action Mailbox feature. It allowed routing incoming emails to controller-like mailboxes - for every new email, there now was an InboundEmail record created that could be processed later on. Action Mailbox by default uses Active Storage to keep messages in the cloud and automatically provides a background job for deleting old emails. Moreover, it integrates easily with the most popular transactional email services like Mailgun, SendGrid, Mandrill, Postmark, and allows to handle emails directly with Postfix, Exim, or Qmail. The only disadvantage: using Action Mailbox requires Rails 6, which can be hard to achieve if you are maintaining old applications with legacy code.

To sum up: use Action Mailbox if you can, otherwise keep reading to see other solutions!

Solution 1: Third-party integration with Griddler

This was the most common solution before Rails 6. Basically, developers built a similar mechanism to what Action Mailbox provides but using a ruby gem called Griddler. It adds an endpoint for receiving messages and lets the developer define a class that will be responsible for processing messages later on (like creating a database entry with an email body or sending an automatic reply). It’s also possible to easily integrate Griddler with transactional email services like Sendgrid or Mailgun (there are even dedicated gem versions, like griddler-sendgrid or griddler-mandrill). Disadvantages? It’s a little outdated. According to The Ruby Toolbox page, it has a low commit activity in the last 3 years and no release in over a year.

To sum up: a little outdated, but still a usable alternative for Action Mailbox.

Solution 2: IMAP protocol

IMAP (Internet Message Access Protocol) was created in 2003. Its goal was to define how email communication across all the web should work. So why don’t use it directly? Without a doubt, the most popular is a ruby built-in library Net::IMAP. It allows all basic operations provided by the aforementioned protocol, like connecting to the IMAP server, getting a list of inboxes, fetching email messages, etc. Unfortunately, using it is a bit troublesome: protocol itself is a little enigmatic, Net::IMAP library documentation could be more precise and, most importantly, it doesn’t provide some features of modern email inboxes, like handling attachments or connecting via SSL (or requires a significant amount of work to add them). Building a complex solution based on Net::IMAP library requires much work and should be considered only when other solutions are not viable (or as an interesting side project).

To sum up: Net::IMAP is for very simple use cases or for radical geeks who want to implement everything on their own.

Solution 3: AWS SES

Amazon Simple Email Service allows cost-effective handling of emails: both incoming and outgoing. It integrates very well with other AWS services (eg. S3, Lambda) and provides lots of flexibility in terms of architecture design. Building an AWS SES-based email processor with Rails application could be more complex than the options mentioned above and will require some knowledge about AWS infrastructure, but will also allow creating a well-tailored solution. This was the path my team chose when implementing an email receiver (after creating a prototype and confirming that it meets all requirements). We integrated AWS SES with S3 for storing all incoming messages and with Lambda function, which is invoked every time a new message comes. Then, Lambda saves information about new emails to the database which is used by the Rails application. In the end, the whole architecture is very flexible and extendable - I will present its details in the next blog post. :)

To sum up: AWS SES is the best solution for more complex systems, which already use AWS infrastructure.

Summary

There are many different options to implement email receiving in Ruby on Rails applications. Probably the easiest and most straightforward one is picking Action Mailbox, but it might be not possible for applications with older versions of Rails. In such cases, one should consider other circumstances, such as architecture dependencies, specific feature requirements, or even budget to choose the most suitable solution.

Michał Łęcicki
Ruby Developer

Check my Twitter

Check my Linkedin

Did you like it? 

Sign up To VIsuality newsletter

READ ALSO

How to become a Ruby Certified Programmer Title image

How to become a Ruby Certified Programmer

14
.
11
.
2023
Michał Łęcicki
Ruby
Visuality
Vector Search in Ruby - Paweł Strzałkowski

Vector Search in Ruby

17
.
03
.
2024
Paweł Strzałkowski
ChatGPT
Embeddings
Postgresql
Ruby
Ruby on Rails
LLM Embeddings in Ruby - Paweł Strzałkowski

LLM Embeddings in Ruby

17
.
03
.
2024
Paweł Strzałkowski
Ruby
LLM
Embeddings
ChatGPT
Ollama
Handling Errors in Concurrent Ruby, Michał Łęcicki

Handling Errors in Concurrent Ruby

14
.
11
.
2023
Michał Łęcicki
Ruby
Ruby on Rails
Tutorial
Recap of Friendly.rb 2024 conference

Insights and Inspiration from Friendly.rb: A Ruby Conference Recap

02
.
10
.
2024
Kaja Witek
Conferences
Ruby on Rails

Covering indexes - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Ruby on Rails
Postgresql
Backend
Ula Sołogub - SQL Injection in Ruby on Rails

The Deadly Sins in RoR security - SQL Injection

14
.
11
.
2023
Urszula Sołogub
Backend
Ruby on Rails
Software
Michal - Highlights from Ruby Unconf 2024

Highlights from Ruby Unconf 2024

14
.
11
.
2023
Michał Łęcicki
Conferences
Visuality
Cezary Kłos - Optimizing Cloud Infrastructure by $40 000 Annually

Optimizing Cloud Infrastructure by $40 000 Annually

14
.
11
.
2023
Cezary Kłos
Backend
Ruby on Rails

Smooth Concurrent Updates with Hotwire Stimulus

14
.
11
.
2023
Michał Łęcicki
Hotwire
Ruby on Rails
Software
Tutorial

Freelancers vs Software house

02
.
10
.
2024
Michał Krochecki
Visuality
Business

Table partitioning in Rails, part 2 - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Backend
Postgresql
Ruby on Rails

N+1 in Ruby on Rails

14
.
11
.
2023
Katarzyna Melon-Markowska
Ruby on Rails
Ruby
Backend

Turbo Streams and current user

29
.
11
.
2023
Mateusz Bilski
Hotwire
Ruby on Rails
Backend
Frontend

Showing progress of background jobs with Turbo

14
.
11
.
2023
Michał Łęcicki
Ruby on Rails
Ruby
Hotwire
Frontend
Backend

Table partitioning in Rails, part 1 - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Postgresql
Backend
Ruby on Rails

Table partitioning types - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Postgresql
Backend

Indexing partitioned table - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Backend
Postgresql
SQL Views in Ruby on Rails

SQL views in Ruby on Rails

14
.
11
.
2023
Jan Grela
Backend
Ruby
Ruby on Rails
Postgresql
Design your bathroom in React

Design your bathroom in React

14
.
11
.
2023
Bartosz Bazański
Frontend
React
Lazy Attributes in Ruby - Krzysztof Wawer

Lazy attributes in Ruby

14
.
11
.
2023
Krzysztof Wawer
Ruby
Software

Exporting CSV files using COPY - Postgres Stories

14
.
11
.
2023
Jarosław Kowalewski
Postgresql
Ruby
Ruby on Rails
Michał Łęcicki - From Celluloid to Concurrent Ruby

From Celluloid to Concurrent Ruby: Practical Examples Of Multithreading Calls

14
.
11
.
2023
Michał Łęcicki
Backend
Ruby
Ruby on Rails
Software