Sending Emails in Rails with Action Mailer and Gmail
tuckersteil
Posted on April 19, 2023
This post will describe how to set up and send a confirmation email, when a customer books a training session.
The steps:
- Set up a mailer with rails generate mailer
- Create email templates (views)
- Tell the appropriate controller action to send the email
- Configure the mail settings for Gmail.
Let's assume we have an app that allows users to book a training session and that we already have a basic Order model and controller setup, which when booked creates and new instance of Order.
class OrdersController < ApplicationController
def new
@order = Order.new
end
def create
@order = Order.new(order_params)
if @order.save
render json: @order
else
render json: { errors: @booking.errors.full_messages }, status: :unprocessable_entity
end
end
private
def order_params
params.require(:order).permit(:name, :email, :address, :phone, :message)
end
end
In addition to created the instance of Order, we want to be able to send the user an email confirmation for the order.
To get started, we first need to create a mailer:
$ rails generate mailer OrderMailer
This will create the following files and output:
create app/mailers/order_mailer.rb
invoke erb
create app/views/order_mailer
invoke test_unit
create test/mailers/order_mailer_test.rb
create test/mailers/previews/order_mailer_preview.rb
Then navigate to the "app/mailers" folder and select the application_mailer.rb:
class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com' # Replace this email address with your own
layout 'mailer'
end
The "default from:" is where you add the email address you want to send the emails from. So can either be a business email or personal.
Now we need to go into the actual order_mailer.rb and add a method to the mailer to send emails:
class OrderMailer < ApplicationMailer
def new_order_email
@order = params[:order]
mail(to: @order.email, subject: "You got a new order!")
end
end
The key here is to set the "mail(to: @order.email". This will be the email(email we are sending to) that is sent from the order controller when a new instance is being created. Any instance variables in new_order_email can be used in the mailer views. The params[:order] will be provided when we tell the OrderController to send the email.
Let's create an email view file now, making sure to name the file the same as the method. Make a new_order_email.html.erb in the app/views/order_mailer/ folder:
# app/views/order_mailer/new_order_email.html.erb
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
</head>
<body>
<p>You placed a new order!</p>
<p>
Order details<br>
--------------------------
</p>
<p>Name: <%= @order.name %></p>
<p>Email: <%= @order.email %></p>
<p>Address: <%= @order.address %></p>
<p>Phone: <%= @order.phone %></p>
<p>
Message:<br>
----------
</p>
<p><%= @order.message %></p>
</body>
</html>
Now that we have the emails set up, next we'll tell the OrdersController to send an email when an order is made, that is, after an order is saved in the create action.
class OrdersController < ApplicationController
def create
@order = Order.new(order_params)
if @order.save
OrderMailer.with(order: @order).new_order_email.deliver_later
render json: @order
else
render json: { errors: @booking.errors.full_messages }, status: :unprocessable_entity
end
end
....
end
Here, we added the following line of code after the order was saved:
OrderMailer.with(order: @order).new_order_email.deliver_later
Notice the with(order: @order) code. This is what gives the OrderMailer access to the order info as a param. Remember setting the instance variable with @order = params[:order] in the OrderMailer? That's where the param is coming from!
Lastly, we need to configure our Rails app to send emails via Gmail. To do so, we'll add the following settings to our config/environments/production.rb:
# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
host = 'example.com' #replace with your own url
config.action_mailer.default_url_options = { host: host }
# SMTP settings for gmail
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:user_name => <gmail_username>,
:password => <gmail_password>,
:authentication => "plain",
:enable_starttls_auto => true
}
For local use only or development use, use:
host = 'localhost:3000'
config.action_mailer.default_url_options = { :host => 'localhost:3000', protocol: 'http' }
Replace and with your own username and password, which would preferably be hidden away as environment variables. Note on the password: I highly recommend enabling 2-Step Verification and registering an "app password" to use in the app or you're likely to run into problems with Gmail blocking the emails.
If you are using 2-step verification, here's how you set it up:
If your Gmail account uses 2-step verification, you will need to get an app password and use that instead of your regular password. If you don't use 2-step verification, I recommend turning it on to avoid getting the emails blocked by Google.
To create an app password, go to your Google account settings and navigate to the "Security" tab. Under "Signing in to Google", click on the "App passwords" menu item (this will only be available if you have 2-step verification turned on). Next, select Other (Custom name) under the "Select app" dropdown and enter the name of your app or something else useful. Click "Generate" and your new app password will appear on the screen. Make sure you copy it before closing the window, or you won't be able to see the password again.
Now, in your Rails app mailer settings, replace the with the new app password instead.
Conclusion
We know have a fully functional mailer that notifies our customer of their order they placed. Once the Rails mailer and Gmail settings are properly configured, we can easily send other emails from other controller actions by generating and setting up new mailers in much the same way
Posted on April 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024