Send with your stack

Send emails with Ruby

Send email from Ruby or Rails with the official mailblastr gem — zero runtime dependencies, plain-hash params, and typed errors.

The official `mailblastr` gem is the fastest way to send email from Ruby. It has zero runtime dependencies — only net/http, json and openssl from the standard library — so it drops into a Rails app, a Sinatra service, or a bare script without pulling anything else in.

One thing to know up front: the gem is configured at the module level (Mailblastr.api_key = ...) rather than by constructing a client object, and every resource is a module method — Mailblastr::Emails.send, Mailblastr::Contacts.create, and so on. Note the capitalisation: the constant is Mailblastr, with a lowercase b.

Prerequisites

  1. A verified domain for your from address. (guide)
  2. An API key (mb_...), read from ENV["MAILBLASTR_API_KEY"] or Rails credentials. (Authentication)
  3. Ruby 2.7 or newer — that is the floor declared by the gemspec (required_ruby_version).

Install

gem install mailblastr

Or add it to your Gemfile and run bundle install:

Gemfile
gem "mailblastr", "~> 5.0"

Configure

Set the key once at boot. Mailblastr.api_key = ... on its own is enough; the configure block is the same assignment with room for the optional settings.

config/initializers/mailblastr.rb
require "mailblastr"

Mailblastr.configure do |config|
  config.api_key = ENV.fetch("MAILBLASTR_API_KEY")

  # Optional:
  # config.base_url    = "https://www.mailblastr.com/api" # override the API host
  # config.timeout     = 10 # seconds per attempt (default 30; 0 disables)
  # config.max_retries = 3  # 429/503 retry budget (default 2)
end
Outside Rails, put the same lines wherever your process boots. Configuration is process-global and there is no client object to thread through your code, so Mailblastr::Emails.send works from anywhere once the key is set. Call it before setting the key and the gem raises a Mailblastr::Error whose name is missing_api_key — it fails locally rather than spending a request, which is also why that one error has a nil #status_code.

Send an email

Params are a plain hash with snake_case keys, passed through as JSON. delivered@mailblastr.dev is MailBlastr's mailbox simulator — the send is accepted, produces a real email object and a delivery event, and never reaches a provider, so it is safe to send to while you wire things up. Do not point a send at example.com: those recipients are suppressed and the call comes back 422 validation_error having sent nothing.

send.rb
require "mailblastr"

Mailblastr.api_key = ENV.fetch("MAILBLASTR_API_KEY")

begin
  sent = Mailblastr::Emails.send({
    from: "Acme <hello@yourdomain.com>",
    to: ["delivered@mailblastr.dev"],
    subject: "Hello from Ruby",
    html: "<p>Sent with the official Ruby gem 💎</p>"
  })

  puts "Sent email #{sent['id']}"
rescue Mailblastr::Error => e
  warn "MailBlastr #{e.status_code} #{e.name}: #{e.message}"
end

Handling the response

A successful call returns the parsed JSON body — a Hash with string keys, so the id is sent["id"] and not sent[:id]. Keep it to retrieve the email later or to correlate webhook events.

{
  "id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794"
}

Any non-2xx answer raises Mailblastr::Error, which carries the API's { statusCode, name, message } envelope as #status_code, #name and #message. Branch on #name together with #status_code, never on #message — message text is scrubbed server-side and is not a stable contract. Plan and quota rejections additionally populate #limit and reputation gates populate #reputation; both are nil on an ordinary error, and #body is the whole parsed body so a field newer than your gem version is still reachable.

begin
  Mailblastr::Emails.send(params)
rescue Mailblastr::Error => e
  case e.name
  when "validation_error"
    # 422 — a bad field (and 403 on a raw request with no User-Agent).
  when "daily_quota_exceeded", "monthly_quota_exceeded", "plan_limit_reached"
    if (cap = e.limit)
      warn "#{cap['kind']} cap hit: #{cap['used']}/#{cap['limit']}"
    end
  when "missing_api_key", "invalid_api_key", "restricted_api_key"
    # 401/403 — the key is absent, wrong, or lacks the scope for this route.
  else
    raise
  end
end

From a Rails controller or job

With the initializer above in place there is nothing else to wire up. Send from a background job so a slow API call never blocks the request.

app/jobs/welcome_email_job.rb
class WelcomeEmailJob < ApplicationJob
  queue_as :mailers

  def perform(user)
    sent = Mailblastr::Emails.send(
      {
        from: "Acme <hello@yourdomain.com>",
        to: [user.email],
        subject: "Welcome to Acme",
        html: "<p>Hi #{CGI.escapeHTML(user.first_name.to_s)}, thanks for signing up.</p>"
      },
      { idempotency_key: "welcome-#{user.id}" }
    )

    user.update!(welcome_email_id: sent["id"])
  end
end

The second argument is an options hash. idempotency_key is honoured by Mailblastr::Emails.send and Mailblastr::Batch.send only — a retry with the same key replays the original response instead of sending twice. It must be 1–255 characters (Mailblastr::Client::IDEMPOTENCY_KEY_MAX_LENGTH); the server answers anything else with 400 invalid_idempotency_key.

The gem sets a User-Agent on every request (mailblastr-ruby/5.1.0), which the API requires on every route — a request without one is rejected with 403 validation_error before it is even authenticated. It also retries 429 and 503 automatically, honouring Retry-After, up to Mailblastr.max_retries times (default 2). Nothing else is retried — not a timeout, not a network error, not any other status — so a send is never silently duplicated.
Keep the mb_ API key server-side — in Rails credentials or an environment variable, never in client-side code or version control. Anyone with the key can send email as you.

Next steps

  • Send up to 100 messages in one request with Mailblastr::Batch.send([...]). Batch items reject attachments and scheduled_at — send those one at a time.
  • See the full Send Email API reference for every body field (cc, bcc, reply_to, attachments, scheduled_at).
  • Explore the SDKs reference for the other resources the gem exposes — contacts, segments, campaigns, templates, automations, webhooks and events.
  • Verify inbound webhooks with Mailblastr::Webhooks.verify(raw_body, headers, signing_secret) — pass request.raw_post, never re-serialized JSON. See Webhooks.
  • Prefer no gem at all? Send with Ruby over raw HTTP uses only net/http.