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.

Ruby
# app/services/avelto.rbrequire "net/http"require "json"module Avelto  API = "https://api.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}")  endend

2. 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:

shell
export AVELTO_API_KEY=av_test_...

3. Send your first email

A controller action that sends and returns the API's answer, or the error envelope with the same status.

Ruby
# app/controllers/emails_controller.rbclass 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  endend
Ruby
# config/routes.rbpost "/send", to: "emails#create"get "/emails/:id", to: "emails#show"

Run bin/rails server and call the action:

shell
curl -X POST http://localhost:3000/send

The API answers 201 Created with the email id, and the action returns the same:

HTTP
HTTP/1.1 201 CreatedContent-Type: application/json{ "id": "9c1f4a52-6f6e-4b8f-9b8e-2e1a5c7d3f10" }

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.

Ruby
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"] }  }end
shell
curl http://localhost:3000/emails/9c1f4a52-6f6e-4b8f-9b8e-2e1a5c7d3f10

5. Verify a domain

Adding a domain is a one-off task, so it fits a rake task. Publish the DNS records it prints (an ownership TXT, an SPF TXT and a DMARC TXT, then three DKIM CNAMEs once the ownership record is found) 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.

Ruby
# lib/tasks/avelto.rakenamespace :avelto do  desc "Add a sending domain and wait until it is verified"  task :verify, [:name] => :environment do |_t, args|    show = lambda do |d|      d["dns_records"].each do |r|        puts [r["type"], r["name"], r["value"], "(#{r['purpose']})"].join("\t")      end    end    domain = Avelto.create_domain(args[:name])    show.call(domain) # the ownership record first, with SPF and DMARC    # Publish the records, then poll. GET re-checks DNS on every call.    # Once the ownership record is found, the DKIM records appear: publish those too.    while domain["status"] == "pending"      sleep 30      latest = Avelto.get_domain(domain["id"])      show.call(latest) if latest["ownership_verified"] && !domain["ownership_verified"]      domain = latest    end    puts domain["status"] # "verified" or "failed"  endend
shell
bin/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.