How to send emails from Rails app via Google SMTP server
In this tutorial, we will create a Rails application using Rails Action Mailer to send emails via Google SMTP server.
Prerequisites
You can do this tutorial on a Linux, Mac, or Windows workstation.
Outline
- Sending emails in a Rails application
- Creating the Rails application
- Creating the subscriber resource in Rails
- Creating an Action Mailer
- Sending emails via Gmail SMTP server
- Configuring SMTP server settings in Rails
- Sending an email when creating a new article
- Sending emails in a production Rails application
Sending emails in a Rails application
Sending out emails is a common requirement in web applications.
Email is the preferred communication channel for informing readers on new blog posts, updating customers on order status, notifying users on their account activites, etc.
Sending emails in Rails is easy.
Rails Action Mailer packs the email handling functions in Rails such that sending an email in Rails is not very different from rendering an HTML view.
In this tutorial, we will create a simple blog in Rails. When a new article is published, we will notify our readers by sending an email via Google SMTP server.
Creating the Rails application
Install Ruby on the development workstation by following the installation instructions. My preferred choice is rbenv but there are several other options as well.
Install Rails:
$ gem install rails
This will install the latest version of Ruby on Rails.
Create a new Rails app:
$ rails new my-blog
This will create a new Rails application in my-blog
directory.
Run the rails server:
$ cd my-blog
$ bin/rails server
Visit URL http://127.0.0.1:3000
to make sure that our new Rails app is working fine.
Create an Article
scaffold:
$ bin/rails generate scaffold articles title:string content:text
The generate scaffold
command creates the Model, View, Controller, and the Active Record migrations for the Article
resource. This Article
resource has two fields title
and content
of type string
and text
respectively.
Run the Article
resource migrations:
$ bin/rails migrate
Running the migration creates the database table for the Article
resource.
At this point, we have a Rails application where we can create new articles and save. Let’s try that.
Run the rails server:
$ bin/rails server
To create new article, go to URL http://127.0.0.1:3000/articles
and click on New article
link.
Enter some text for Title
and Content
fields, and click on the Create article
button.
Rails saves the new article and redirects us to the URL http://127.0.0.1:3000/articles/1
.
Creating the subscriber resource in Rails
We need to send an email to our subscribers when we publish a new article. So, let’s create a subscriber
resource using the generate scaffold
command:
$ bin/rails generate scaffold subscribers name:string email:string
Run the migrations:
$ bin/rails db:migrate
Let’s create a new subscriber.
Go to URL http://127.0.0.1:3000/subscribers
in the browser and click on New subscriber
link.
Enter Name
and Email
and click on Create Subscriber
button. You need to enter a valid email address that can receive emails.
Creating an Action Mailer
Rails Action Mailer implements the email handling capability in Rails.
Rails Action Mailer works similar to a Rails controller. While a Rails controller render an HTML view, an Action Mailer sends an email.
To use Action Mailer we must create a new Mailer for the Article
resource:
$ bin/rails generate mailer Article
This creates two files application_mailer.rb
and article_mailer.rb
inside the app/mailers
directory.
The artilce_mailer.rb
defines the ArticleMailer
class. To send an email we must create a method in this class.
Create new_article_email
method:
class ArticleMailer < ApplicationMailer
default from: 'news@cloudqubes.com'
def new_article_email
@article = params[:article]
Subscriber.all.each do |subscriber|
mail(to: subscriber.email, subject: @article.title)
end
end
end
The default
method sets the default value for the from
header in the email.
The new_article_email
method sends an email using the mail
method in Action Mail.
The params hash allows us to pass an instance of an Article
to the ArticleMailer
. We assign an instance variable @article
so we can access the Article instance in the Mailer View which we will create next.
A Mailer View defines the content of an email.
For the ArticleMailer, we must create the Mailer Views inside app/views/article_mailer
directory.
The new_article_email
method in the ArticleMailer looks for Mailer views starting with file name new_article_email.*
inside app/views/article_mailer
.
Let’s create a new file new_article_email.html.erb
inside app/views/article_mailer
:
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
</head>
<body>
<h1><%= @article.title %></h1>
<p>
<%= @article.content %>
</p>
</body>
</html>
In the Mailer view, we have used the @article
variable which we created in the new_article_email
method. This is quite similar to how we assign instance variables in Rails controllers and use those variables inside views.
Not all email clients support HTML, so we must create a text view also to send a text version of our email.
Create new_article_email.text.erb
file inside ‘app/views/article_mailer`:
<%= @article.title %>
--------------------------------------------------------------------------------
<%= @article.content %>
Now, we have the email content defined in the Mailer views.
Sending emails via Gmail SMTP server
We will use Gmail SMTP server to send emails.
If you don’t have a Google account (I would really like to hear from you 😧) create one now.
To use the SMTP server, we must create an App password in our Google account.
Before creating an App password, we must enable two-step verification in Google account authentication. Or, Google will not allow us to create an App password.
Sign in to your Google account and click on the profile icon on the top right. Click on Manage your Google account
.
Click on Security
in the left navigation menu. Click on 2-Step Verification
and follow the instructions to enable two-step verification for your Google account. You can select a phone number or an authenticator app as the second verification step.
Select the Authenticator app option and you’ll be prompted with a QR code, which you must scan via an authenticator app in your phone. Install the Google Authenticator App on your phone and scan the QR code.
The Authenticator app will generate a code. Enter this code in your 2-step verification settings to complete the two-step verification setup.
If you use a phone number Google will send the verification code to your phone via a text message. I’ve found that spam filtering or other filtering mechanisms in some telecom service providers block such text messages. So, I suggest using an authenticator app instead of a phone number.
After configuring the two-step verification, go to Create and manage your app passwords to create an App password.
Type in a name for your app and click on the Create
button. Google will create an app password like abcd efgh ijkl mnop
. Copy this password to a secure location. Once created, you cannot view an app password in Google. If you forgot the app password, you must create a new app password.
Configuring SMTP server settings in Rails
We need to securely store our Google account app password inside the Rails app. So, we use Rails encrypted credentials.
Open Rails credentials for editing:
EDITOR="vi" rails credentials:edit
This will decrypt and open config/credentials.yml.enc
file in vi
editor.
Add the Google username and app password.
smtp:
username: username@gmail.com
password: abcd efgh ijkl mnop
Replace username
with your Google username and abcd efgh ijkl mnop
with your app password.
Save and close the vi
editor.
Open config/environments/development.rb
and add the SMTP configuration.
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:user_name => Rails.application.credentials.dig(:smtp, :username),
:password => Rails.application.credentials.dig(:smtp, :password),
:authentication => "plain",
:enable_starttls_auto => true
}
We are using the values we configured in the Rails credentials for the username
and password
fields.
Sending an email when creating a new article
We need to send an email when creating a new article.
So, let’s add the code to send an email, inside the create
method in the articles_controller.rb
.
# app/controllers/articles_controller.rb
...
def create
@article = Article.new(article_params)
respond_to do |format|
if @article.save
ArticleMailer.with(article: @article).new_article_email.deliver_later
format.html { redirect_to article_url(@article), notice: "Article was successfully created." }
format.json { render :show, status: :created, location: @article }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @article.errors, status: :unprocessable_entity }
end
end
end
...
ArticleMailer.with
method creates a new instance of the ArticleMailer and assigns the params
hash to which we pass an instance of the newly created Article.
The deliver_later
method creates a background job to send the emails in the background. We can use the method deliver_now
to send the email without creating a background job. Then, the rest of the code inside the create
method will not run until all the emails are sent out and our user may have to wait indefinitely to get the response after creating the article, which is not acceptable.
Run the Rails app:
$ bin/rails server
Go to URL http://127.0.0.1:3000/articles
and click on New article
link. Update some values for the Title
and the Content
fields and click on Create article
button.
Check the output in the terminal.
Rails will print this when Action Mailer sends out the email.
[ActiveJob] [ActionMailer::MailDeliveryJob] [<job_id>] Performed ActionMailer::MailDeliveryJob (Job ID: <job_id>) from Async(default) in 4156.22ms
Check your email account for the email from your Rails app.
Sending emails in a production Rails application
In this tutorial, we used the deliver_later
method to send emails in a background job. Rails relies on Active Job to run such background jobs.
Since we had only one subscriber in this setup, our background job was completed in no time. But a Rails blog application in production may need to send thousands of emails in a single job which could take hours to complete.
In the development mode, Rails Active Job runs background jobs in an in-memory thread pool. This mode is unsuitable for production, as any uncompleted jobs would be lost if the Rails application is restarted.
To handle background jobs in production, we must use an Active Job adapter that uses persistent storage. But, that’s the work for a separate tutorial in the future.