Sign in to fill these examples with your own keys. Sign in Start free trial

Send emails with Rails

Deliver with Action Mailer and delivery_method = :postshiba.

What you'll build

An Action Mailer mailer that delivers through PostShiba instead of SMTP. Your existing mailers, views, and deliver_later jobs keep working.

Before you start

  • An API key with Send only access. Full access also works. See Create an API key. Support keys cannot send.
  • A verified sending domain. See Add and verify a domain. from must be an address on it.
  • A cluster that is ready to send (sending_ready is true). See Clusters.
  • Ruby 3.1 or later.

Install

The gem is on GitHub, not RubyGems. Add it to your Gemfile, then run bundle install. It registers the :postshiba delivery method with Action Mailer.

Gemfile
1gem "postshiba", git: "https://github.com/postshiba/postshiba-ruby.git"

Send your first email

This file sets the delivery method, defines a mailer, and sends one message. Run it with bin/rails runner send.rb.

send.rb
1ActionMailer::Base.delivery_method = :postshiba 2ActionMailer::Base.postshiba_settings = {api_key: "YOUR_API_KEY"} 3 4class ReceiptMailer < ApplicationMailer 5 def receipt 6 headers["X-Capsule-Unique-Args"] = {order_id: "ord_123"}.to_json 7 mail( 8 from: "hello@mail.example.com", 9 to: "you@example.com", 10 reply_to: "support@example.com", 11 subject: "Your receipt" 12 ) do |format| 13 format.text { render plain: "Thanks for your order." } 14 format.html { render html: "<p>Thanks for your order.</p>".html_safe } 15 end 16 end 17end 18 19ReceiptMailer.receipt.deliver_now

The message then shows under Events in the dashboard. deliver_now returns the Mail::Message, not the API response.

The adapter turns Reply-To into reply_to and X-Capsule-Unique-Args into unique_args on the POST /api/v1/emails body. Other custom headers are sent as headers.

Configure your app

In an app, set the delivery method once in config/environments/production.rb and keep the key in credentials.

production.rb
1config.action_mailer.delivery_method = :postshiba 2config.action_mailer.postshiba_settings = { 3 api_key: Rails.application.credentials.dig(:postshiba, :api_key) 4}

postshiba_settings also accepts cluster_id, team_id, and base_url.

Pin a cluster

Without a pin, PostShiba uses your first cluster that is ready to send. Set cluster_id in postshiba_settings, or set X-Capsule-Cluster-Id on one message. The header wins and is sent as an HTTP header, not in the body.

pin_mailer.rb
1mail(from: "hello@mail.example.com", to: "you@example.com", subject: "Your invoice") 2 .tap { |message| message["X-Capsule-Cluster-Id"] = "NmQpXr" }

Deliver in the background

Swap deliver_now for deliver_later and Active Job sends it from your queue.

deliver_later.rb
1ReceiptMailer.receipt.deliver_later

Attachments and templates

Attach a file

Use Action Mailer's attachments. The adapter base64-encodes each file for the API. Up to 10 files, 18 MB in total. See Attachments for allowed types.

receipt_mailer.rb
1def receipt 2 attachments["invoice.pdf"] = File.binread(Rails.root.join("tmp/invoice.pdf")) 3 mail(from: "hello@mail.example.com", to: "you@example.com", subject: "Your invoice") 4end

Use a view

Put the HTML in app/views/receipt_mailer/receipt.html.erb and drop the format block. Action Mailer finds the view by method name. Hosted PostShiba templates go through the Ruby client with template, not through Action Mailer.

receipt.html.erb
1<p>Thanks for your order.</p>

Keep the key safe

Use a Send only key in your app. It can send email and call GET /api/v1/users/me. Every other request returns 403 forbidden.

If this key leaks Send only Full access
Send mail from your verified domains Yes Yes
Read events, recipients, templates, and sent messages No Yes
See SMTP passwords and webhook secrets No Yes
Change clusters, domains, credentials, webhooks, and suppressions No Yes
  • Keep Full access keys for setup scripts, the CLI, and MCP. Don't deploy one with your app.
  • Keep the key in Rails credentials, as in Configure your app, or read it from an environment variable such as ENV.fetch("POSTSHIBA_API_KEY"). Don't commit the key or config/master.key, log the key, or put it in a URL. The "YOUR_API_KEY" literal in send.rb is for a quick test only.
  • Send from your server. Never put a key, even a Send only key, in a view, browser code, or mobile code.
  • Create one key per app and environment. Per-environment credentials such as config/credentials/production.yml.enc keep them apart. If a key leaks, delete it on API keys and create a new one. Deleting stops it straight away.

Troubleshooting

A failed send raises PostShiba::Error from deliver_now when raise_delivery_errors is on. error and field come from the JSON body.

Status error What to do
401 Invalid token or no user signed in The API key is missing, mistyped, or deleted. Copy it again from API keys.
403 forbidden Support keys cannot send. Use a Send only or Full access key. A Send only key gets this on any call other than sending.
403 domain_unverified from is not on a verified domain.
403 kyc_required Your team is pending production approval. Until then, send only to team members, live inbox addresses, and inbox forward-to addresses.
422 invalid field names the problem, such as a missing to or a rejected attachment.
429 throttled The cluster hit its hourly throttle or 24-hour cap. Retrying right away hits the same cap. If you use deliver_later, retry the job after the hour. See What happens at your cap.
429 rate_limited More than 300 send requests in one minute on one API key. Slow down.

Every other status is on Errors.

Next steps