Tutorial
Enviar emails con Ruby on Rails
Entrega el correo de Action Mailer a través de Emailit con la gema emailit o la configuración SMTP, llama directamente a la API y verifica los webhooks de Emailit en Rails.
En esta guía se explica cómo enviar el correo de Rails a través de Emailit. Puedes usar el método de entrega de Action Mailer de la gema emailit, que envía a través de la API, o apuntar la configuración SMTP de Action Mailer al relay de Emailit. También se explica cómo llamar directamente a la API y cómo verificar los webhooks.
Requisitos previos
- Ruby 3.0 o posterior y una aplicación Rails.
- Un dominio de envío verificado, por ejemplo
acme.com. - Una clave de API. Basta con una clave Sending Only limitada a tu dominio.
- Hasta que tu espacio de trabajo tenga acceso de producción, solo puedes enviar a las direcciones de email de las cuentas de los miembros del espacio de trabajo.
Instalar la gema
bundle add emailitLa gema no tiene dependencias en tiempo de ejecución aparte de la biblioteca estándar de Ruby.
Configurar la clave de API
Guarda la clave en tu entorno o en las credenciales de Rails:
bin/rails credentials:editemailit:
api_key: secret_••••••••••••••••••••••••••••••••
webhook_secret: whsec_••••••••Los ejemplos siguientes leen Rails.application.credentials.dig(:emailit, :api_key). Si usas variables de entorno, lee en su lugar ENV.fetch("EMAILIT_API_KEY").
Enviar con Action Mailer
Cuando la gema detecta Rails, registra un método de entrega :emailit. Actívalo en cada entorno:
config.action_mailer.delivery_method = :emailit
config.action_mailer.emailit_settings = {
api_key: Rails.application.credentials.dig(:emailit, :api_key)
}Tus mailers no cambian. La dirección from debe pertenecer a un dominio de envío verificado:
class UserMailer < ApplicationMailer
default from: "Acme <hello@acme.com>"
def welcome(user)
@user = user
mail(to: @user.email, subject: "Welcome to Acme")
end
endUserMailer.welcome(user).deliver_laterEl método de entrega convierte cada mensaje en una petición a la API, con from, to, cc, bcc, reply_to, el asunto, las partes HTML y de texto, y los adjuntos.
Llamar directamente a la API
Para las funciones que Action Mailer no contempla, como las plantillas guardadas o los envíos programados, usa el cliente:
client = Emailit::EmailitClient.new(Rails.application.credentials.dig(:emailit, :api_key))
email = client.emails.send(
from: "Acme <hello@acme.com>",
to: user.email,
template: "welcome",
variables: { first_name: user.first_name },
scheduled_at: "tomorrow at 9am"
)
email.id # => "em_…"Los errores se lanzan como excepciones tipadas: Emailit::AuthenticationError (401), Emailit::RateLimitError (429), Emailit::UnprocessableEntityError (422) y Emailit::ApiError para todo lo demás.
Enviar por SMTP
Para usar SMTP sin más, configura la entrega SMTP de Action Mailer:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.emailit.com",
port: 587,
user_name: "emailit",
password: Rails.application.credentials.dig(:emailit, :api_key),
authentication: :plain,
enable_starttls_auto: true
}Los mailers y deliver_later funcionan igual. Si tu proveedor de hosting bloquea el puerto 587, usa el 2525 o el 2587. Consulta Configuración SMTP.
Recibir webhooks
Crea un webhook que apunte a https://your-app.com/webhooks/emailit. Añade una ruta y un controlador que verifique la firma con el cuerpo en bruto:
post "/webhooks/emailit", to: "emailit_webhooks#create"class EmailitWebhooksController < ActionController::API
def create
payload = request.raw_post
signature = request.headers["X-Emailit-Signature"].to_s
timestamp = request.headers["X-Emailit-Timestamp"].to_s
return head :unauthorized unless valid_signature?(payload, signature, timestamp)
# The body is a JSON array of up to 100 events.
JSON.parse(payload).each do |event|
case event["type"]
when "email.bounced", "email.complained"
address = event.dig("data", "object", "to")
# Stop emailing this address.
end
end
head :ok
end
private
def valid_signature?(payload, signature, timestamp)
return false if signature.empty? || timestamp.empty?
return false if (Time.now.to_i - timestamp.to_i).abs > 300
secret = Rails.application.credentials.dig(:emailit, :webhook_secret)
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{timestamp}.#{payload}")
ActiveSupport::SecurityUtils.secure_compare(expected, signature)
end
endAl heredar de ActionController::API se omite la protección CSRF, que Emailit no puede satisfacer. Devuelve un 2xx en menos de 30 segundos y pasa el trabajo lento a Active Job. Consulta Firma de las peticiones.
Consejos para producción
- Entrega más tarde. Usa
deliver_laterpara que las peticiones web no esperen al email, y limita el ritmo de los jobs masivos para no superar tus límites de envío (2 emails por segundo por defecto). - Mantén el desarrollo seguro. En desarrollo, usa
:letter_opener,:testo una clave de preproducción aparte para no enviar emails a usuarios reales por accidente. - Elimina los webhooks duplicados. Guarda cada
event_idque procesas; las entregas fallidas se reintentan y pueden llegar más de una vez. - Rota las claves sin interrupciones desplegando una clave nueva antes de eliminar la antigua. Consulta Claves de API.