Content outline

Jul 21, 2024
10 Min read

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.

Rails logo with text Action Mailer

Prerequisites

You can do this tutorial on a Linux, Mac, or Windows workstation.

Outline

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.

Rails default home page

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.