Send emails from Ruby
Transactional and marketing email from Ruby services and background jobs. One HTTP call, and a message ID you can follow to the inbox.
✓Free to start. Unlimited contacts on every tier.
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 / 04 ]Quickstart
How do I send email from Ruby?
Three steps from no account to a queued email. No gem needed.
Create an API key
In the dashboard, open Settings → API & MCP and create a key with the Send + manage permission (the default). It starts with aem_ and is shown once.
Store it as an environment variable
Keep the key on your server, never in front-end code. Your code reads it with ENV.fetch('AEM_KEY').
Terminalexport AEM_KEY="aem_..."Send the email
POST the recipient and a published template. Anything but a 2xx raises, and a retry with the same Idempotency-Key won't send a second email.
send_welcome.rbrequire 'json' require 'net/http' uri = URI('https://sendandretain.com/api/v1/emails') headers = { 'Authorization' => "Bearer #{ENV.fetch('AEM_KEY')}", 'Content-Type' => 'application/json', 'Idempotency-Key' => "welcome-#{user.id}" } body = { to: user.email, template: 'welcome' }.to_json response = Net::HTTP.post(uri, body, headers) raise "Send failed: #{response.code} #{response.body}" unless response.is_a?(Net::HTTPSuccess)Keep the message ID
A 202 means queued, not delivered. Store the id; delivery, bounce, and complaint events arrive later on your signed webhook.
202 Accepted{ "id": "msg_7ca31", "status": "queued" }
[ 02 / 04 ]In production
What does a production Ruby integration need?
A service object, not a callback
Put the request in one service with the key, timeout, and error handling, not in a model callback.
Retries with the same key
Enqueue an Active Job or Sidekiq job after commit. Retry timeouts and 5xx errors with the same Idempotency-Key; don't retry validation or auth errors.
Webhooks checked on the raw body
Use request.raw_post to verify the signature, and skip forgery protection on that route only.
Events for marketing email
Send product events like signup or trial started. Automations you've turned on decide which email goes out.
[ 03 / 04 ]Example prompts
What can you ask your coding agent to do in Ruby?
Paste these into Claude Code, Cursor, or Codex. Connect the MCP server and it can build the templates and automations too.
Welcome email
“Find where we create users and send a welcome email with the Send & Retain API from a service object. Use the user ID as the idempotency key.”
Sidekiq
“Move our email sends into a Sidekiq job enqueued after commit, retrying timeouts with the same Idempotency-Key and never retrying 4xx errors.”
Webhooks
“Add a Rails controller that verifies Send & Retain webhook signatures on request.raw_post and flags bounced addresses on our users.”
Trial automation
“Send a trial_started event to Send & Retain when a trial begins, then build a paused trial automation for it.”
Questions people ask us
Send your first email from Ruby.
Create a key, make one call, and follow the message ID to the inbox.