Inbound email in Rails apps with Fuik
Fuik is a Rails engine for handling webhooks that I launched recently. But it can also be used to process inbound emails! 💡
When working with inbound email in Rails using Action Mailbox, there’s a key requirement: managing EML files and blob storage. Once an email arrives at your domain, your email provider captures it and sends the data to you via webhook. You then extract what you need and process (or store) it. Action Mailbox requires: ActiveStorage ánd ActionMailer.
But what if you don’t have a need for ActiveStorage (including its cloud storage setup) or ActionMailer (because you use Courrier).
Most transactional email providers send their inbound emails as webhooks: Postmark, SendGrid, Mailgun and Mailpace. They all POST the email data to a webhook URL you configure.
Fuik is great at capturing just that: it captures those incoming webhooks, stores them in the database and calls your event class to process them. You see all your webhooks in at /webhooks. You can inspect and copy payloads, pull path accessors and generally debug what’s happening.
It is simple to get started:
bundle add fuik
bin/rails generate fuik:install
bin/rails db:migrate
That’s it. Your app now has /webhooks endpoints ready to receive any webhooks. Now to process inbound emails, let’s look at Postmark as an example (though every provider that sends inbound emails as webhooks wil work).
Postmark lets you receive inbound emails by pointing a MX record to their servers and then configure a webhook URL. When an email arrives, the data is POSTed to you. Let’s see how to process it in your app with Fuik.
Generate the class:
bin/rails generate fuik:provider postmark inbound_email
This creates three files.
Now open app/webhooks/postmark/inbound_email.rb. Postmark sends "To", "From", "Subject", "TextBody", and "HtmlBody". Route emails based on the recipient address:
module Postmark
class InboundEmail < Base
def process!
return if to_email.blank?
case to_email
when /replies-.*@/
message = Message.find_by(email_address: to_email)
message.replies.create!(
content: text_content,
from: from_email
)
when /support@/
SupportTicket.create!(
from: from_email,
subject: subject,
body: text_content
)
end
@webhook_event.processed!
end
private
def to_email = payload["To"]
def from_email = payload["From"]
def subject = payload["Subject"]
def text_content = payload["TextBody"]
end
end
Postmark doesn’t send an event type in the payload (all inbound webhooks are inbound emails), so you set it statically. Use Fuik’s config (app/webhooks/postmark/config.yml) to extract it:
event_type:
source: static
value: inbound_email
Point your Postmark inbound webhook to https://yourdomain.com/webhooks/postmark in their dashboard, and emails start flowing in.
In the repo shared, I also added an example for Sendgrid to show another example how to do this.
Any provider with webhooks
Postmark and SendGrid are just examples. Mailgun, Brevo, Mailpace and others all send structured JSON via webhooks. The pattern is the same. Generate a provider, map the payload fields to your private methods, add your business logic and mark the event as processed.
Check out the example repository with both Postmark and SendGrid set up.
Want to read me more?
-
Announcing Fuik: a webhook engine for Rails
Fuik automatically captures webhook payloads and provides a beautiful UI to process them. -
Using Subdomains in Rails: Development vs Production
A clean and simple approach to make work with subdomains locally. -
Simple Stripe Billing for Rails
Getting paying users has never been simpler with Stripe and Rails. Let's go over the tiny amount of code needed today.
Over to you…
What did you like about this article? Learned something knew? Found something is missing or even broken? 🫣 Let me (and others) know!
Comments are powered by Chirp Form
{{comment}}