Usando Mandrill desde Rails
Introducción a Mandrill
En una aplicación Rails, normalmente usaríamos Amazon SES para enviar los mails transaccionales. Amazon funciona bien y es económico, pero muchas veces el cliente quisiera ver reportes de los envíos o quisiera poder editar un poco el template del correo que envía su aplicación. El objetivo de este post es explicar cómo enviar los mails de una aplicación Rails a través del servicio que ofrece mandrill.com.
Api Keys
Puedes crear api keys con algunas opciones. Algo muy util es la opción de “test” para un api-key, que usa una dimensión paralela para probar todo sin mandar mails de verdad. Perfecto para desarrollo.
Habilitar dominios
Puedes autorizar múltiples dominios. Fácilmente se siguen las instrucciones para además configurar correctamente el DKIM y SPF.
Se puede usar el API HTTP de Mandrill o las credenciales SMTP para enviar los mails. Nosotros preferimos el uso del API HTTP.
Templates
Puedes crear tantos templates como la aplicación requiera. En cada template debes preocuparte de dejar publicada una versión que tenga al menos:
- Un contenido básico
- From Address
- From Name
- Subject
Si no defines esos valores, el mail no se mandará ( y ojo, que el error es un poco invisible).
Templates Dinámicos
En Mandrill puedes usar dos tipos de lenguajes para templates. Handlebars y el que se usa en Mailchimp. El primero es más poderoso (condicionales, loops, etc…), pero tuvimos problemas cuando lo usamos con Mailchimp para exportar los templates a Mandrill.
Con Handlebars los templates se ven así:
Hola {{user_name}},Acabas de comprar estos productos:{{#products}}
<ul>
<li>{{this}}</li>
</ul>
{{/products}}
Exportando los templates de Mailchimp
Es súper básica la edición de los templates dentro de Mandrill. Es por eso que se pueden exportar los templates desde Mailchimp. Con esta guía queda muy claro como hacerlo.
Ojo, que no logramos usar handlebars desde acá!
Api Logs
Existe una sección para ver todas las llamadas al API, con error y con éxito.
Integración con Rails via SMTP
Mandrill se puede utilizar como un servidor SMTP común y corriente, configurando action_mailer como en el siguiente ejemplo
config.action_mailer.delivery_method = :smtpconfig.action_mailer.smtp_settings = {
address: ENV.fetch("SMTP_SERVER"), # smtp.mandrillapp.com
authentication: :plain,
enable_starttls_auto: true,
password: ENV.fetch("MANDRILL_APIKEY"),
port: "587",
user_name: ENV.fetch("MANDRILL_USERNAME") # login email en mandrill
}
Con eso estamos listos para usar los Mailers existentes de Rails y enviarlos con Mandrill.
Pero como queremos utilizar MailChimp para gerenciar los templates de cada tipo de email, no enviaremos emails por SMTP, sino usando la API HTTP de Mandrill
Integración con Rails usando API Http
Setup inicial
- Agregar la gema mandrill-api en el Gemfile
- Setear las variables en .rbenv-vars
MANDRILL_APIKEY=XXX
Creando el MandrillMailer
Este módulo será la base para mandar emails usando los templates de Mandrill desde otros Mailers.
require "mandrill"module MandrillMailer
def send_mail(to, template_name, attributes)
return if Rails.env.test?
mandrill = Mandrill::API.new(ENV["SMTP_PASSWORD"])merge_vars = attributes.map do |key, value|
{ name: key, content: value }
endto = [to] unless to.is_a?(Array)
recipients = to.map { |email| { "email" => email, "type" => "to" } }message = {
"global_merge_vars" => merge_vars,
"to"=> recipients
}
results = mandrill.messages.send_template template_name, [], message
if results.any?{|result| !result["reject_reason"].nil? }
Rails.logger.info "Couldn't send all emails: #{results}"
endrescue Mandrill::Error => e
# Mandrill errors are thrown as exceptions
puts "A mandrill error occurred: #{e.class} - #{e.message}"
# A mandrill error occurred: Mandrill::UnknownSubaccountError - No subaccount exists with the id 'customer-123'
raiseendend
Utilizando un Mailer normal
Podemos utilizar un nuevo Mailer o crear uno y debemos incluir el módulo en el mailer como en este ejemplo:
class PetsMailer < ActionMailer::Base
include MandrillMailerdef for_adoption(pet_shop, cats)# build a list of cats with only the desired data to pass
list = cats.map do |cat|
{
name: cat.name,
age: cat.age
}
end# all template vars
template_vars = {
"cats" => list,
"shop_name" => pet_shop.name
}send_mail(pet_shop.email, "adopt-a-cat-template", template_vars)
end
Se puede ver que no estamos utilizando el clásico método mail de ActionMailer sino send_mail. Este método recibe 3 parametros.
- to: Puede ser una dirección de mail(string) o un arreglo de direcciones
- template: El nombre del template(slug) a utilizar en el envío
- template_vars: Este es un diccionario(Hash) con las variables necesarias en el template. En el ejemplo. cats es un arreglo con hashes y shop_name es solo un string
Utilizando en Devise Mailer
Para utilizar Mandrill con Devise, necesitamos crear un Mailer que herede de Devise::Mailer y configurarlo en Devise
# initializers/devise.rb
config.mailer = 'MyDeviseMailer'
Tenemos que reimplementar cada tipo de mail que queramos utilizar con Mandrill, en el ejemplo la recuperación de password y confirmación de cuenta.
Si es que estuviera habilitado otro tipo de mail de devise, no pasaría por Mandrill (Como ser send_unlock_instructions) y se enviaría por SMTP directamente.
class MyDeviseMailer < Devise::Mailer
include MandrillMailer
helper :applicationdef reset_password_instructions(record, token, opts={})
template_vars = {
"user_name" => record.display_name,
"reset_link" => edit_user_password_url(record, reset_password_token: token)
}send_mail(record.email, "recover-password-slug", template_vars)
enddef confirmation_instructions(record, token, opts={})
template_vars = {
"user_name" => record.display_name,
"confirm_link" => new_user_confirmation_url(record, confirmation_token: token)
}send_mail(record.email, "confirm-account-slug", template_vars)
endend