Send email with Ruby on Rails

A service object called from a background job, with the key in credentials.

You need a verified sending domain and an API key from Settings › API Keys. If neither exists yet, the quickstart covers both in a couple of minutes.

Send

require "net/http"
require "json"
 
class WelcomeEmail
  ENDPOINT = URI("https://sending.dev/api/v1/emails")
 
  def self.deliver(user)
    request = Net::HTTP::Post.new(ENDPOINT)
    request["Authorization"] = "Bearer #{Rails.application.credentials.sending_api_key}"
    request["Content-Type"] = "application/json"
    request.body = {
      from: "Acme <[email protected]>",
      to: user.email,
      subject: "Welcome",
      html: "<p>You're in.</p>",
      idempotencyKey: "welcome-#{user.id}"
    }.to_json
 
    Net::HTTP.start(ENDPOINT.host, ENDPOINT.port, use_ssl: true) do |http|
      http.request(request)
    end
  end
end

A successful call answers 202 with the message id: accepted and queued, not yet delivered. Delivery, opens, bounces and complaints arrive later, on webhooks or in the dashboard.

What changes in Ruby on Rails

Call it from an ActiveJob, not from the controller. Rails credentials keep the key encrypted in the repository, which is the one place a key can safely live in version control.

The thing that catches people

ActionMailer is not in this path: previews, deliver_later and the test adapter do not apply. If you want both, keep transactional email here and leave ActionMailer for internal mail.

Next

  • All the fields: cc and bcc, reply-to, attachments, templates, scheduling.
  • Webhooks: delivery, bounce and complaint events, signed with HMAC.
  • Domains: SPF, DKIM and MAIL FROM, and why sending is refused until they are in place.
  • MCP: the same operations as tools, when the one writing the code is an agent.

Nearby: PHP and Ruby

All 30 stacks