Tutorial: Enviar Emails Transaccionales con Ruby on Rails

Hola! hoy vamos a hacer una pequena aplicacion para enviar emails transaccionales usando la API de Mandrill y Ruby on Rails. Pues basicamente todos los usuarios registrados en la aplicacion van a recibir multiples articulos relacionados a sus intereses. 

Para esto basicamente tengo un modelo: Usuario, y Articulo. Esto puede ser cambiado de acuerdo a sus necesidades. El mail de resultado es el siguiente,q claro puede ser fomateado como uds. prefieran:






Debe haber muchas formas de lograr esto, pero bueno no encontre mucha informacion y por eso me motive a escribir este tutorial. Comencemos!!

1.- Tienen que inscribirse en Mandrill by Mailchimp, y conseguir una API Key. Un tutorial basico  de como trabajar con Mandrill lo pueden encontrar AQUI

2.- En la configuracion de rails en la carpeta: "config/environments/"  van a encontrar varios archivos: test, development y production. Para hacer pruebas de desarrollo en el archivo de development vamos a crear la siguiente variable de ambiente, con su api key:

     ENV['MANDRILL_APIKEY'] = "xxxxxxFbLIadw-r1Nxw" 


3.- En el controlador debe haber un "require mandrill" para poder trabajar con la API.

4.- En el controlador anadimos el metodo para procesar o enviar los mails 


 def process_email(templates)
    # send a new message
    m = Mandrill::API.new
    message = { 
      :subject=> "News from The Digest", 
      :from_name=> "TheDigest",
      :from_email=>"hello@thedigest.com",
      :to=>convert_users_to_mandrill_recipients(templates),
      :html=>render_to_string('subscriptions/template_email.html.erb', :layout => false), 
      :merge_vars => to_mandrill_merge_vars(templates),
      :preserve_recipients => false
    } 
    sending = m.messages.send message
  end    

Vamos a explicar un poco como funciona:
Primero, este metodo recibe un arreglo de templates, cuya estructura basica es la siguiente:

 name = "Angela C."
email = "angela.carrera@gmail.com"
 articles = [id:1, 
             summary:"Articulo de ejemplo1",
             id:2,
             summary:"Articulo de ejemplo2"]

Esto puede ser adaptado a ordenes, facturas etc, de acuerdo a sus necesidades.


5.- Si nos fijamos en la parte de to, especificamos los destinatarios con el metodo  convert_users_to_mandrill_recipients, que se encarga de obtener un arreglo de emails para que mandrill lo pueda leer como lista de destinatarios.


  # Obtener lista de destinatarios para  Mandrill API
  def convert_users_to_mandrill_recipients(templates)
     templates.map do |user|     
     {:email => user.email}
     end
  end

6.- En la parte de html utilizamos la opcion render_to_string que basado en un view previamente creado, genera un html, que es el que se enviara a cada uno de los usuarios. Adicional a eso usamos la opcion layout => false para especificar que no vamos a usar los layouts de navegacion o cabecera que se utilizan en todas las vistas de rails. 

7.- La template que he usado es la siguiente: template_email.html.erb


<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h2> Hi, *|first_name|* </h2>
    <p>
     *|HTML:body|*    
     <br>
     <p> Best Regards, <br>
     The Digest </p>
  </body>
</html>

En el template tenemos las variables *|first_name|*  y *|HTML:body|*,  en esta ultima enviaremos un html q contenga el detalle de todos los articulos de interes para el usuario, que estan en el arreglo articulos. 

8.- Por ultimo tenemos en merge_vars la llamada al metodo to_mandrill_merge_vars
    # Unir las plantillas con variables
  def to_mandrill_merge_vars(templates) 
    templates.map {|template| {:rcpt => template.email, :vars => [{:name => 'first_name', :content => template.name},{:name => 'body', :content => get_html(template)}]}} 
  end

  # Obtener html basado en los articulos del arreglo
  def get_html(template)
    if !template.articles.empty?
      html = render_to_string(:template => 'subscriptions/template_interest.html.erb', :locals => { :templates => template } , :layout => false)
    else
      html = "You don't have new content available. </br> We will return with news of your interest!!!"
    end
    return html
  end

Expliquemos un poco, en el metodo to_mandrill_merge_vars, este metodo se encargara de devolver un hashmap que contenga el mail, y el remplazo de las variables que hemos puesto en nuestro template: first_name y body. En el caso de body enviamos el arreglo template que contiene a su vez nuestro arreglo de articulos. Para ello usamos el metodo get_html, en este metodo si el arreglo de articulos esta vacio se le envia una notificacion al usuario de que no tiene contenido disponible. 
Si tiene articulos, utilizamos de nuevo la opcion render_to_string y llamamos a la view template_interest.html.erb que va a tener el formato de una vista cualquiera de rails, y es la que pongo a continuacion como referencia. 


   <% templates.articles.each do |article| %>
  <div class="panel panel-default">
  <div class="panel-body">
    <h2><%= article.title %> </h2></br>
    <small>Posted On: <%= article.created_at.strftime("%Y %m %d")%></small>
    <% if article.img_url != nil %>
    <div style="float:left">
    <p><%= image_tag article.img_url, height: '80', width: '70'%></p>
    </div>
    <% end %>
    <p align=justify>&nbsp;&nbsp;&nbsp;<%= article.summary %></p>  
    <p>
    <small>More details..</small>
    <a href="<%= article.url %>"><%= article.url %></a>
    </p>  
  </div>
   <div class="panel-footer">
    Author: <%=article.author %>
    <span style="float:right;"> Source: <%=article.source %> </span>  
    </div> 
</div>
<% end %>



Y bueno eso es todo! Espero que les sea de utilidad. Y cualquier duda no duden en escribirnos, en facebook o aqui!

PD: Disculpen si hay partes en ingles pero actualmente estudio una carrera q es toda en ingles.

Comentarios