Send Rails email without hiding network work in a callback. Service object first, ActiveJob when durability matters.
Keep the send explicit, hand durable work to your job backend, and follow each accepted message ID through the same lifecycle history as the customer.
✓Use it beside or instead of Action Mailer when product email needs lifecycle context and a delivery trail.
One request, complete trace
Request
POST /api/v1/emails
Authorization: Bearer aem_…
Idempotency-Key: welcome-8f21
{ "to": "[email protected]", "template": "welcome" }
202 Accepted
{ "id": "msg_7ca31", "status": "queued" }
[ 01 / 03 ]Integration shape
Make email an explicit application action.
Use mailers, jobs, and service objects
A service object keeps the decision visible; ActiveJob hands durable execution to Sidekiq, Solid Queue, or your chosen backend.
Publish product events
Publish lifecycle events after commit instead of triggering external calls from model callbacks that may run inside a transaction.
Verify the webhook
A controller action with skip_forgery_protection and request.raw_post for signature verification.
[ 02 / 03 ]Server quickstart
Queue one Rails email with a retry-safe key.
Reuse the logical key if ActiveJob retries, and retain the accepted ID when application state needs a delivery reference.
Put the request in a service or background job rather than a model callback.
request = Net::HTTP::Post.new(URI(EMAIL_URL))
request['Authorization'] = "Bearer #{ENV.fetch('AEM_KEY')}"
request['Idempotency-Key'] = "welcome-#{user.id}"
request['Content-Type'] = 'application/json'
request.body = { to: user.email, template: 'welcome' }.to_jsonAccepted response
{ "id": "msg_7ca31", "status": "queued" }[ 03 / 03 ]Related
Keep building with Rails
Questions people ask us
Make your next Rails email explicit and traceable.
Queue it after commit, reuse the key on retries, and verify the final delivery event.