ActionMailer config vs one POST
ActionMailer earns its keep for templated app mail inside Rails, but it still rides on SMTP settings: address, port, user_name, password, authentication, enable_starttls_auto. Six config keys before the first send, and rotating credentials touches every environment.
One POST, and the send is handled
require "net/http" require "json" Net::HTTP.post( URI("https://api.nitrosend.com/v1/my/messages"), { from: "[email protected]", to: "[email protected]", subject: "Welcome", html: "<p>You're in.</p>" }.to_json, "Authorization" => "Bearer #{ENV['NITROSEND_API_KEY']}", "Content-Type" => "application/json", )
Works from Rails, Sinatra, a Rake task, or a bare script. One env var, standard library only.
For scale of what sits behind that POST: I recently watched four flows and fourteen emails get designed, written, and set sending in about twenty-three minutes. Builders who grew up on Rails scaffolding will recognize the feeling.
And here's the part Ruby people will enjoy: the API on the other end of that POST is a Rails 8.1 app, PostgreSQL and GoodJob underneath. Your Net::HTTP call is speaking to a stack you already know how to reason about.
A design detail from inside that codebase: every production send path, campaign, flow, transactional, and the MCP tool included, runs through one central sending gate, a single check on every dispatch. A paused account fails loudly with metadata saying exactly why, instead of six code paths each deciding for themselves. And when SES suppresses a recipient mid-flow, the failure is written to the send log and that branch stops, without failing the whole GoodJob run. Rails people know why both of those matter.
The email renderer is Ruby too. When an agency customer reported that images set to 50% width came out full size in Gmail, the root cause was our renderer stripping the px unit and re-appending it, so 50% became 50%px. The fix went through nitrosend/api#80 with the image spec at 19 of 19 green, and the supported width shapes are now pinned to exact strings: 300, 300px, 50% and 12.5px preserved, garbage like calc(100%) dropped.
The whole surface is inspectable. The API publishes its own OpenAPI document at api.nitrosend.com/openapi.yaml, a Rails health check at /up, and every REST route under /v1/my. Nothing about the stack is hidden from the person integrating it.
Full parameters, responses, and error codes live in the REST API docs and the API reference.
And the part no library gives you
The same account exposes an MCP server, so the agent writing your code can also run your email. Point Claude, Cursor, or Codex at api.nitrosend.com/mcp and it composes, previews, and stages sends, with a human approving every one. The API is for your code. The MCP is for your agent. One platform either way.
Every send comes back with a message ID, and delivery events follow on your webhook: delivered, opened, bounced. No dashboard required to know what happened. If you are staying on SMTP, how to set up SMTP is the setup to follow, and SPF, DKIM and DMARC authentication is what stops those sends landing in spam.
Net::SMTP or a gem is a Ruby developer's call to make, and it always has been. It increasingly isn't a developer making it. Point Claude, Cursor, or Codex at our MCP server and the agent composes the send, picks the transport, and asks you to approve it before it leaves. I think that's the real direction email sending is heading, and it's why Nitrosend is a listed app in the ChatGPT app marketplace rather than one more gem to bundle install.
Go deeper
FAQ
How do I send email from Ruby?
POST to the email API with Net::HTTP or Faraday: JSON body, bearer token header, message ID back. No SMTP settings block, no delivery mystery.
Can I keep ActionMailer?
Yes, point its delivery method at the API or keep it for templating and deliver through the REST endpoint. The win is dropping SMTP credentials and gaining delivery events.