Send email from Rails with emailr_
Send Action Mailer email from Rails through the emailr_ API with a custom delivery method, deliver_later support and signed webhook verification.
Rails apps already describe email with Action Mailer. Instead of rewriting mailers, register a small custom delivery method that hands each rendered message to the emailr_ API. deliver_now and deliver_later keep working.
There's no Ruby gem yet, so the delivery method calls POST https://api.emailr.dev/v1/emails/send with Net::HTTP from the standard library.
Set up emailr_ with Rails
- 01
Create an API key
Create a key under API keys in the dashboard. Keys start with
et_live_and are scoped to one domain workspace. Store it asEMAILR_API_KEYin your secret manager or environment, never in client-side code. - 02
Add and verify your sending domain
In the dashboard, open Domains and add the domain you send from. A subdomain such as
mail.yourcompany.comkeeps transactional reputation separate from your corporate mailbox.Emailr generates the DNS records: a DKIM TXT record on the
emailr._domainkeyselector, an SPF TXT record, and an MX + TXT pair on thesendsubdomain used as the MAIL FROM / Return-Path. A DMARC record is optional but recommended.Emailr's DKIM selector and
sendsubdomain don't collide with other providers' records, so you can add them before cutting over and send from both providers during the migration. A domain can only have one SPF record: if one already exists, merge Emailr'sinclude:into it instead of adding a second record. - 03
Store the key
Put
EMAILR_API_KEYandEMAILR_WEBHOOK_SECRETin your environment or Rails credentials. - 04
Add a delivery method
Action Mailer calls
deliver!with a renderedMail::Message. Pull out the HTML and text parts and post them as JSON. Raising on a non-2xx response lets Active Job retrydeliver_laterjobs.lib/emailr_delivery.rbrubyrequire "net/http" require "json" class EmailrDelivery ENDPOINT = URI("https://api.emailr.dev/v1/emails/send") def initialize(settings) @api_key = settings.fetch(:api_key) end def deliver!(mail) html = mail.html_part&.decoded || (mail.mime_type == "text/html" ? mail.decoded : nil) text = mail.text_part&.decoded || (mail.mime_type == "text/plain" ? mail.decoded : nil) payload = { from: mail[:from].value, to: mail.to, cc: mail.cc, bcc: mail.bcc, subject: mail.subject, html: html, text: text, reply_to_email: mail.reply_to&.first, }.compact response = Net::HTTP.post( ENDPOINT, payload.to_json, "Authorization" => "Bearer #{@api_key}", "Content-Type" => "application/json", ) raise "Emailr error #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess) end end - 05
Register it
Register the method in an initializer and select it for the environments that should send real email.
config/initializers/emailr.rbrubyrequire Rails.root.join("lib/emailr_delivery") ActionMailer::Base.add_delivery_method :emailr, EmailrDelivery, api_key: ENV.fetch("EMAILR_API_KEY", nil) # config/environments/production.rb # config.action_mailer.delivery_method = :emailr - 06
Verify delivery webhooks
Use
request.raw_postfor the HMAC and skip CSRF protection for this controller only.app/controllers/emailr_webhooks_controller.rbrubyclass EmailrWebhooksController < ActionController::API def create payload = request.raw_post expected = OpenSSL::HMAC.hexdigest("SHA256", ENV.fetch("EMAILR_WEBHOOK_SECRET"), payload) signature = request.headers["X-Emailr-Signature"].to_s unless ActiveSupport::SecurityUtils.secure_compare(expected, signature) return head :unauthorized end event = JSON.parse(payload) # event["event"] is e.g. "email.bounced"; details are in event["data"] head :ok end end # config/routes.rb # post "/webhooks/emailr", to: "emailr_webhooks#create"
Tips
- Inheriting from
ActionController::APIskips CSRF checks; if you inherit fromApplicationController, addskip_forgery_protection. - Attachments added with
attachments[...]aren't forwarded by this minimal delivery method. Add them as{ filename:, content: Base64.strict_encode64(...), contentType: }if you need them. - Keep the
:testdelivery method in your test environment so specs never call the API.
Frequently asked questions
Can I keep using Action Mailer with emailr_?
Yes. A custom delivery method sends each rendered mailer through the emailr_ API, so your mailers, views and deliver_later calls stay the same.
Is there a Ruby gem for emailr_?
Not yet. The REST API is small enough to call with Net::HTTP, as shown in this guide.
Does deliver_later retry failed sends?
Yes, if the delivery method raises. Active Job retries according to your queue adapter's settings.
How do I verify emailr_ webhooks in Rails?
Compute OpenSSL::HMAC.hexdigest('SHA256', secret, request.raw_post) and compare it to the X-Emailr-Signature header with ActiveSupport::SecurityUtils.secure_compare.
Keep going
Related guides
- Send email from LaravelSend transactional email from Laravel with the emailr_ HTTP API: render Mailables, queue sends with jobs and verify signed delivery webhooks.
- Send email from FastAPISend transactional email from FastAPI with the async emailr_ Python SDK, run sends as background tasks and verify signed delivery webhooks.
- Send email from AWS LambdaSend transactional email from AWS Lambda with the emailr_ SDK, process SQS batches with partial failure reporting and handle signed webhooks.
Start sending in minutes
Create a free account, verify your domain and send your first email. No credit card required.