Ruby on Rails
ActionMailer
Buscar..
Introducción
Action Mailer le permite enviar correos electrónicos desde su aplicación usando clases y vistas de correo. Los mailers funcionan de manera muy similar a los controladores. Heredan de ActionMailer :: Base y viven en aplicaciones / correos, y tienen vistas asociadas que aparecen en aplicaciones / vistas.
Observaciones
Es recomendable procesar el envío de correo electrónico de forma asíncrona para no bloquear su servidor web. Esto se puede hacer a través de varios servicios, como delayed_job
.
Correo Básico
Este ejemplo utiliza cuatro archivos diferentes:
- El modelo de usuario
- El usuario de correo
- La plantilla html para el correo electrónico.
- La plantilla de texto plano para el correo electrónico.
En este caso, el modelo de usuario llama al método approved
en la aplicación de correo y pasa la post
que ha sido aprobada (el método approved
en el modelo puede llamarse mediante una devolución de llamada, desde un método de controlador, etc.). Luego, el remitente genera el correo electrónico desde la plantilla html o de texto sin formato utilizando la información de la post
aprobada (por ejemplo, el título). De manera predeterminada, la aplicación de correo usa la plantilla con el mismo nombre que el método en la aplicación de correo (por lo que tanto el método de envío como las plantillas tienen el nombre "aprobado").
user_mailer.rb
class UserMailer < ActionMailer::Base
default from: "[email protected]"
def approved(post)
@title = post.title
@user = post.user
mail(to: @user.email, subject: "Your Post was Approved!")
end
end
usuario.rb
def approved(post)
UserMailer.approved(post)
end
homologado.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Post Approved</title>
</head>
<body>
<h2>Congrats <%= @user.name %>! Your post (#<%= @title %>) has been approved!</h2>
<p>We look forward to your future posts!</p>
</body>
</html>
validado.erb
Congrats <%= @user.name %>! Your post (#<%= @title %>) has been approved!
We look forward to your future posts!
Generando un nuevo correo
Para generar un nuevo correo, ingrese el siguiente comando
rails generate mailer PostMailer
Esto generará un archivo de plantilla en blanco en app/mailers/post_mailer.rb
llamado PostMailer
class PostMailer < ApplicationMailer
end
También se generarán dos archivos de diseño para la vista de correo electrónico, uno para el formato html y otro para el formato de texto.
Si prefiere no utilizar el generador, puede crear sus propios correos. Asegúrese de que heredan de ActionMailer::Base
Agregando Adjuntos
ActionMailer
también permite adjuntar archivos.
attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
De forma predeterminada, los archivos adjuntos se codificarán con Base64
. Para cambiar esto, puede agregar un hash al método de adjuntos.
attachments['filename.jpg'] = {
mime_type: 'application/gzip',
encoding: 'SpecialEncoding',
content: encoded_content
}
También puede agregar archivos adjuntos en línea
attachments.inline['image.jpg'] = File.read('/path/to/image.jpg')
ActionMailer Callbacks
ActionMailer soporta tres devoluciones de llamada
- antes_acción
- after_action
- alrededor de la acción
Proporcionar estos en su clase de correo
class UserMailer < ApplicationMailer
after_action :set_delivery_options, :prevent_delivery_to_guests, :set_business_headers
Luego crea estos métodos bajo la palabra clave private
private
def set_delivery_options
end
def prevent_delivery_to_guests
end
def set_business_headers
end
end
Generar un boletín programado
Crear el modelo de boletín :
rails g model Newsletter name:string email:string subl app/models/newsletter.rb validates :name, presence: true validates :email, presence: true
Crear el controlador del boletín :
rails g controller Newsletters create class NewslettersController < ApplicationController skip_before_action :authenticate_user! before_action :set_newsletter, only: [:destroy] def create @newsletter = Newsletter.create(newsletter_params) if @newsletter.save redirect_to blog_index_path else redirect_to root_path end end private def set_newsletter @newsletter = Newsletter.find(params[:id]) end def newsletter_params params.require(:newsletter).permit(:name, :email) end end
Después de eso, cambie la vista create.html.erb al nombre nex. Convertiremos este archivo en una vista parcial que se almacenará dentro del Pie de página . El nombre será _form.html.erb .
Cambiar archivo de nombre de: | A: |
---|---|
app / views / newsletters / create.html.erb | app / views / newsletters / _form.html.erb |
Después de eso se establecen las rutas:
subl app/config/routes.rb resources :newsletters
Más adelante, necesitamos configurar el formulario que usaremos para guardar cada correo:
subl app/views/newsletters/_form.html.erb <%= form_for (Newsletter.new) do |f| %> <div class="col-md-12" style="margin: 0 auto; padding: 0;"> <div class="col-md-6" style="padding: 0;"> <%= f.text_field :name, class: 'form-control', placeholder:'Nombre' %> </div> <div class="col-md-6" style="padding: 0;"> <%= f.text_field :email, class: 'form-control', placeholder:'Email' %> </div> </div> <div class="col-md-12" style="margin: 0 auto; padding:0;"> <%= f.submit class:"col-md-12 tran3s s-color-bg hvr-shutter-out-horizontal", style:'border: none; color: white; cursor: pointer; margin: 0.5em auto; padding: 0.75em; width: 100%;' %> </div> <% end %>
Y después de eso, inserte en el pie de página:
subl app/views/layouts/_footer.html.erb <%= render 'newsletters/form' %>
Ahora, instale - letter_opener - para obtener una vista previa del correo electrónico en el navegador predeterminado en lugar de enviarlo. Esto significa que no necesita configurar la entrega de correo electrónico en su entorno de desarrollo, y ya no tiene que preocuparse por enviar accidentalmente un correo electrónico de prueba a la dirección de otra persona.
Primero agregue la gema a su entorno de desarrollo y ejecute el comando bundle para instalarlo.
subl your_project/Gemfile gem "letter_opener", :group => :development
A continuación, establezca el método de entrega en el entorno de desarrollo:
subl your_project/app/config/environments/development.rb config.action_mailer.delivery_method = :letter_opener
Ahora, cree una estructura de Mailer para administrar todos los correos con los que trabajaremos. En la terminal
rails generate mailer UserMailer newsletter_mailer
Y dentro del UserMailer , tenemos que crear un método llamado Newsletter Mailer que se creará para contener dentro de la última publicación del blog y se activará con una acción de rake. Asumiremos que antes tenías una estructura de blog creada.
subl your_project/app/mailers/user_mailer.rb class UserMailer '[email protected]' def newsletter_mailer @newsletter = Newsletter.all @post = Post.last(3) emails = @newsletter.collect(&:email).join(", ") mail(to: emails, subject: "Hi, this is a test mail.") end end
Después de eso, crea la plantilla de Mailer :
subl your_project/app/views/user_mailer/newsletter_mailer.html.erb <p> Dear Followers: </p> <p> Those are the lastest entries to our blog. We invite you to read and share everything we did on this week. </p> <br/> <table> <% @post.each do |post| %> <%#= link_to blog_url(post) do %> <tr style="display:flex; float:left; clear:both;"> <td style="display:flex; float:left; clear:both; height: 80px; width: 100px;"> <% if post.cover_image.present? %> <%= image_tag post.cover_image.fullsize.url, class:"principal-home-image-slider" %> <%# else %> <%#= image_tag 'http://your_site_project.com' + post.cover_video, class:"principal-home-image-slider" %> <%#= raw(video_embed(post.cover_video)) %> <% end %> </td> <td> <h3> <%= link_to post.title, :controller => "blog", :action => "show", :only_path => false, :id => post.id %> </h3> <p><%= post.subtitle %></p> </td> <td style="display:flex; float:left; clear:both;"> </td> </tr> <%# end %> <% end %> </table>
Como queremos enviar el correo electrónico como un proceso separado, creamos una tarea de Rake para activar el correo electrónico. Agregue un nuevo archivo llamado email_tasks.rake al directorio lib / tasks de su aplicación Rails:
touch lib/taks/email_tasks.rake desc 'weekly newsletter email' task weekly_newsletter_email: :environment do UserMailer.newsletter_mailer.deliver! end
El entorno send_digest_email:: significa cargar el entorno Rails antes de ejecutar la tarea, para que pueda acceder a las clases de la aplicación (como UserMailer) dentro de la tarea.
Ahora, al ejecutar el comando rake -T se listará la tarea Rake recién creada. Probar todo funciona ejecutando la tarea y verificando si el correo electrónico se envía o no.
Para probar si el método de envío de correo funciona, ejecute el comando rake:
rake weekly_newsletter_email
En este punto, tenemos una tarea de rastrillo de trabajo que se puede programar usando crontab . Así que instalaremos la gema cuando se use para proporcionar una sintaxis clara para escribir y desplegar trabajos cron.
subl your_project/Gemfile gem 'whenever', require: false
Después de eso, ejecute el siguiente comando para crear un archivo config / schedule.rb inicial para usted (siempre que la carpeta de configuración ya esté presente en su proyecto).
wheneverize . [add] writing `./config/schedule.rb' [done] wheneverized!
Ahora, dentro del archivo de programación, tenemos que crear nuestro TRABAJO CRON y llamar al método de correo dentro de la determinación del TRABAJO CRON para operar algunas tareas sin asistencia y en un intervalo de tiempo seleccionado. Puede usar diferentes tipos de sintaxis como se explica en este enlace .
subl your_project/config/schedule.rb every 1.day, :at => '4:30 am' do rake 'weekly_newsletter_email' end
Ahora para probar que Cron Job fue creado con éxito, podemos usar el siguiente comando para leer desde la terminal, nuestro trabajo programado en CRON SYNTAX:
your_project your_mac_user$ whenever 30 4 * * * /bin/bash -l -c 'cd /Users/your_mac_user/Desktop/your_project && RAILS_ENV=production bundle exec rake weekly_newsletter_email --silent'
Ahora, para ejecutar la prueba en un entorno de desarrollo, es aconsejable establecer la siguiente línea en el archivo principal application.rb para que la aplicación sepa dónde están los modelos que utilizará.
subl your_project/config/application.rb config.action_mailer.default_url_options = { :host => "http://localhost:3000/" }
Ahora para permitir que Capistrano V3 guarde el nuevo trabajo Cron dentro del servidor y el desencadenante que activará la ejecución de esta tarea, tenemos que agregar el siguiente requisito:
subl your_project/Capfile require 'whenever/capistrano'
E inserte en el archivo de implementación el identificador que CRON JOB usará sobre el entorno y el nombre de la aplicación .
subl your_project/config/deploy.rb set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:rails_env)}" }
Y listo, después de guardar los cambios en cada archivo, ejecute el comando de implementación de capistrano:
cap production deploy
Y ahora su TRABAJO se creó y se calendario para ejecutar el Método Mailer, que es lo que quiero y en el intervalo de tiempo que establecemos en estos archivos.
Interceptor ActionMailer
Action Mailer proporciona enlaces a los métodos de interceptor. Estos le permiten registrar clases que se llaman durante el ciclo de vida de la entrega de correo.
Una clase de interceptor debe implementar el método: deliver_email (message) que se llamará antes de que se envíe el correo electrónico, permitiéndole realizar modificaciones en el correo electrónico antes de que llegue a los agentes de entrega. Su clase debe realizar las modificaciones necesarias directamente en la instancia de Mail :: Message.
Puede ser útil para los desarrolladores enviar correos electrónicos a ellos mismos, no a usuarios reales.
Ejemplo de registro de un interceptor actionmailer:
# config/initializers/override_mail_recipient.rb
if Rails.env.development? or Rails.env.test?
class OverrideMailRecipient
def self.delivering_email(mail)
mail.subject = 'This is dummy subject'
mail.bcc = '[email protected]'
mail.to = '[email protected]'
end
end
ActionMailer::Base.register_interceptor(OverrideMailRecipient)
end