Ruby on Rails
An ActionMailer delivery method, so every existing mailer keeps working.
Register a delivery method and ActionMailer does the rest: your mailers, views, previews, and deliver_later all keep working, and the mail leaves through the API instead of SMTP.
The key
# Rails credentials are the idiomatic place. This opens an editor:
bin/rails credentials:edit
# Add:
# emailssh_api_key: esh_your_key_here
# The key comes from https://emails.sh/dashboard/api-keys.The delivery method
# lib/emailssh_delivery.rb
require 'net/http'
require 'json'
require 'uri'
class EmailsshDelivery
ENDPOINT = URI('https://emails.sh/v1/emails').freeze
def initialize(settings)
@key = settings.fetch(:api_key)
end
# ActionMailer hands us a Mail::Message. Pull out the parts the API wants.
def deliver!(message)
payload = {
from: message[:from].formatted.first,
to: Array(message.to),
subject: message.subject,
html: body_of(message, 'text/html'),
text: body_of(message, 'text/plain')
}.compact
payload[:cc] = Array(message.cc) if message.cc
payload[:reply_to] = Array(message.reply_to).first if message.reply_to
request = Net::HTTP::Post.new(ENDPOINT)
request['Authorization'] = "Bearer #{@key}"
request['Content-Type'] = 'application/json'
request.body = JSON.generate(payload)
response = Net::HTTP.start(ENDPOINT.host, ENDPOINT.port, use_ssl: true, read_timeout: 10) do |http|
http.request(request)
end
return JSON.parse(response.body) if response.is_a?(Net::HTTPSuccess)
refused = JSON.parse(response.body)['error']
raise "emails.sh refused the send: #{refused['code']}: #{refused['message']} #{refused['next']}"
end
private
def body_of(message, mime_type)
return message.body.decoded if message.mime_type == mime_type
message.find_first_mime_type(mime_type)&.decoded
end
end# config/initializers/emailssh.rb
require Rails.root.join('lib/emailssh_delivery')
ActionMailer::Base.add_delivery_method(
:emailssh,
EmailsshDelivery,
api_key: Rails.application.credentials.emailssh_api_key
)# config/environments/production.rb
config.action_mailer.delivery_method = :emailssh
config.action_mailer.default_options = { from: 'Acme <hello@acme.com>' }
config.action_mailer.default_url_options = { host: 'acme.com', protocol: 'https' }Use it
class OrderMailer < ApplicationMailer
def shipped(order)
@order = order
mail(to: order.customer_email, subject: "Order #{order.number} has shipped")
end
end
# In the controller or the job, unchanged from whatever you had before.
OrderMailer.shipped(order).deliver_later