Sending emails in Rails with Action Mailer
In a recent project, as a student in the Software Engineering program at Flatiron, I had the need to send emails from our Rails project. Of course my best references, outside of my instructors video lecture, were the RailsGuides and Google. The task of sending emails can be accomplished using several different gems. This blog will use the ActionMailer gem. As with most things Rails, there is a generator to get you started. In our project, we were trying to send an invoice email to a customer upon service completion.
rails g mailer OwnerInvoiceMailer
This command created the following files and folders in Rails:
app -> mailers -> owner_invoice_mailer.rb
app -> mailers -> application_mailer.rb
app -> views -> owner_invoice_mailer
Mailers function similarly to Controllers. ‘application_mailer’ inherits from ActionMailer: :Base and other mailers inherit from ApplicationMailer. Actions are setup within the specific mailer(in this case, owner_invoice_mailer.rb).
class OwnerInvoiceMailer < ApplicationMailerdefault from: 'flatiron_garage@flatiron_garage.com'def invoice_email@owner = params[:owner]@service_record = params[:service_record]@url = 'http://example.com/login'mail(to: @owner.email, subject: 'Thanks for using Flatiron Garage. Invoice enclosed.')endend
Several parameters, such as default from: and @url can be left as the defaults, but the params[:owner] and params[:service_record] will be needed in the controller action where the email is sent, as well as in the actual email configuration. The mail() method also needs the correct information in order to send to the correct address.
The triggering of our email was from the ‘create’ action in the service_record controller, if the service record was successfully saved. Here is where the actual mailer is invoked.
respond_to do |format|if @service_record.save# Tell the Mailer to send an invoice email after saveOwnerInvoiceMailer.with(owner: @owner, service_record: @service_record ).invoice_email.deliver_nowformat.html { redirect_to service_record_path(@service_record, notice: 'Invoice was successfully sent') }format.json { render json: @owner, status: :created, location: @owner }elseformat.html { render action: 'new' }format.json { render json: @owner.errors, status: :unprocessable_entity }endend
In order to format the email, two files had to be setup within the owner_invoice_mailer folder within views. A standard HTML formatted email and, for those emails systems that do not accept HTML, a plain text formatted email.
invoice_email.html.erb
invoice_email.text.erb
Here is a snippet of the HTML code showing the use of embedded Ruby to dynamically write the email.
<body><h1>Thanks for using Flatiron Garage, <%= @owner.name %></h1><p>Date of service: <%= @service_record.date_of_service%><br><br><%= @owner.name %><br><%= @owner.street_address %><br><%= @owner.city %>, <%= @owner.state %> <%= @owner.zip_code %><br><br>
Embedded Ruby was also used in the plain text version.
Thanks for using Flatiron Garage, <%= @owner.name %>===========================================================Date of service: <%= @service_record.date_of_service %><%= @owner.name %><%= @owner.street_address %><%= @owner.city %>, <%= @owner.state %> <%= @owner.zip_code %><%= @service_record.car.year %>, <%= @service_record.car.make %>, <%= @service_record.car.model%>
Rails is not an email server. A 3rd party email service has to be used. Rails sends the email text and headers to the email server, which formats it into smtp and sends it. Gmail has some functionality that allows it to be used as a 3rd party server. The details of how to set this up in Gmail are beyond the scope of this blog, but Gmail documentation is pretty good. Secure communications between the Rails server and the smtp server were not a concern, but could be the subject of another blog.
This information must be setup in the environment folder in ‘development.rb’ and ‘production.rb’. This is where the connection to the 3rd party server is made. The code is the same in each file. The username and password are changed here for privacy reasons. The password is provided by Gmail or another service.
config.action_mailer.delivery_method = :smtphost = 'localhost:3000'config.action_mailer.default_url_options = {host: host}config.action_mailer.smtp_settings = {address: 'smtp.gmail.com',port: 587,user_name: 'somebody.mail@gmail.com',password: 'udhdyetegsnsjdorm',authentication: 'plain',enable_starttls_auto: true }