Send email from Ruby on Rails
Five steps: add a small client, create a test key, send to the sandbox from a controller, read the log, then verify a domain from a rake task so you can send to anyone.
1. Install
No SDK or gem needed. The API is plain JSON over HTTPS, so Net::HTTP and JSON from the standard library are all it takes. A short module wraps the four calls this page uses; a non-2xx status carries { "error": { "code", "message" } }, which becomes an Avelto::Error.
# app/services/avelto.rb
require "net/http"
require "json"
module Avelto
API = "https://api-staging.avelto.dev"
class Error < StandardError
attr_reader :status, :code
def initialize(status, code, message)
super(message)
@status = status
@code = code
end
end
def self.request(method, path, body = nil)
uri = URI("#{API}#{path}")
klass = method == :post ? Net::HTTP::Post : Net::HTTP::Get
req = klass.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch('AVELTO_API_KEY')}"
req["Content-Type"] = "application/json"
req.body = body.to_json if body
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
http.request(req)
end
data = JSON.parse(res.body)
unless res.is_a?(Net::HTTPSuccess)
error = data["error"]
raise Error.new(res.code.to_i, error["code"], error["message"])
end
data
end
def self.send_email(email)
request(:post, "/v1/emails", email)
end
def self.get_email(id)
request(:get, "/v1/emails/#{id}")
end
def self.create_domain(name)
request(:post, "/v1/domains", { name: name })
end
def self.get_domain(id)
request(:get, "/v1/domains/#{id}")
end
end2. Create an API key
Sign in, open API keys in the dashboard and create a test key. It starts with av_test_. Export it so the app can read it:
export AVELTO_API_KEY=av_test_...Test keys never deliver anything; they run the pipeline and record events. The sandbox sender you@sandbox.avelto.dev only delivers to your account's verified owner email and to the simulator addresses delivered@, bounced@ and complained@sandbox.avelto.dev. Anything else is refused with 403 sandbox_recipient_not_allowed. To send to anyone, verify a domain (step 5).
3. Send your first email
A controller action that sends and returns the API's answer, or the error envelope with the same status.
# app/controllers/emails_controller.rb
class EmailsController < ApplicationController
skip_forgery_protection # so you can try it with curl
def create
email = Avelto.send_email(
from: "you@sandbox.avelto.dev",
to: "delivered@sandbox.avelto.dev",
subject: "Hello from Avelto",
text: "It works."
)
render json: email, status: :created # { "id": "9c1f4a52-..." }
rescue Avelto::Error => e
render json: { error: { code: e.code, message: e.message } }, status: e.status
end
end# config/routes.rb
post "/send", to: "emails#create"
get "/emails/:id", to: "emails#show"Run bin/rails server and call the action:
curl -X POST http://localhost:3000/sendThe API answers 201 Created with the email id, and the action returns the same:
HTTP/1.1 201 Created
Content-Type: application/json
{ "id": "9c1f4a52-6f6e-4b8f-9b8e-2e1a5c7d3f10" }Send an Idempotency-Key header (any unique string, such as your order id) with every POST /v1/emails. If the request times out or comes back 429, 502, 503 or 504, wait a moment and send it again unchanged with the same key: the API returns the original email id instead of sending twice. See Idempotency.
4. Check the log
A show action fetches the email by id. status moves from queued to sent to delivered, and events records each step: email.queued, email.sent, email.delivered.
def show
email = Avelto.get_email(params[:id])
render json: {
status: email["status"], # "queued", then "sent", then "delivered"
events: email["events"].map { |e| e["type"] }
}
endcurl http://localhost:3000/emails/9c1f4a52-6f6e-4b8f-9b8e-2e1a5c7d3f105. Verify a domain
Adding a domain is a one-off task, so it fits a rake task. Publish the DNS records it prints (three DKIM CNAMEs, an SPF TXT and a DMARC TXT) at your DNS provider; the task polls GET /v1/domains/:id, which re-checks DNS on every call, until status is verified. Use a subdomain such as mail.acme.com.
# lib/tasks/avelto.rake
namespace :avelto do
desc "Add a sending domain and wait until it is verified"
task :verify, [:name] => :environment do |_t, args|
domain = Avelto.create_domain(args[:name])
domain["dns_records"].each do |r|
puts [r["type"], r["name"], r["value"], "(#{r['purpose']})"].join("\t")
end
# Publish the records, then poll. GET re-checks DNS on every call.
status = domain["status"]
while status == "pending"
sleep 30
status = Avelto.get_domain(domain["id"])["status"]
end
puts status # "verified" or "failed"
end
endbin/rails "avelto:verify[mail.acme.com]"Once the domain is verified, switch AVELTO_API_KEY to a live key (av_live_) and change from in the controller to an address on it, such as hello@mail.acme.com. Nothing else changes.
Next
- Send email: every field, attachments, tags, scheduling and idempotency.
- Webhooks: get events pushed to your app.
- Test mode: test keys, the sandbox sender and the simulator addresses.