Guides
Send email with Ruby
Net::HTTP and nothing else: one POST, explicit status checks, done.
Facts verified 2026-07-17 — corrections: hello@emailfast.dev
Ruby's Net::HTTP handles the Email Fast API without a single gem: one JSON POST, one bearer header, one status check. If you'd rather have a typed client, the Ruby SDK quickstart covers it; on Rails, the Rails guide wraps this call in a service object and a job.
# send.rb — Ruby 3.x, stdlib only
require "json"
require "net/http"
require "uri"
uri = URI("https://api.emailfast.dev/v1/emails")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("EMAILFAST_API_KEY")}" # ef_sandbox_... while testing
req["Content-Type"] = "application/json"
req.body = JSON.generate(
to: "ada@example.com",
subject: "Welcome",
html: "<h1>Hi {{name}}</h1>",
data: { name: "Ada" },
idempotency_key: "welcome-ada-1" # a retry replays, never re-sends
)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 10) do |http|
http.request(req)
end
raise "Send rejected (#{res.code}): #{res.body}" unless res.is_a?(Net::HTTPSuccess)
result = JSON.parse(res.body)
puts "#{result["id"]} #{result["status"]}" # msg_... queueda 202 from the API means the send is committed to a durable, partitioned outbox before we answer — a crash can't lose it, and a retry with the same idempotency key can't double-send.
Gotchas
Net::HTTPdoes not raise on 4xx/5xx — it hands you the error response and moves on. CheckNet::HTTPSuccessyourself; the JSON body names the exact rejection.use_ssl: trueis not inferred from the URL. Forget it and the request talks plaintext to port 443 and fails confusingly.ENV.fetch(notENV[]) fails loudly at boot when the key is missing — the failure you want.- Sending many? Keep the
Net::HTTP.startblock open and reuse the connection, or POST up to 500 messages to/v1/emails/batchin one call.
Next
- Ruby SDK quickstart — the typed client
- The email API — batch, scheduling, message timelines
- Sending from Rails
- All docs