Automatic Email Notifications for a Rails Comments Section

  • rails, gems, tutorials
  • 1 Comment

When I built the comments section for this blog I wanted to include functionality that automatically sent me an email notification when someone left a comment. This tutorial explains how to use Rails Action Mailer and a Gmail account to generate emails when a visitor posts a comment.

Generate a Mailer

Action Mailer allows a Rails app to send emails using mailer classes and views, and its functionality is similar to a controller. To install a mailer in your app run rails generate mailer CommentsMailer, a command that creates app/mailers/comment_mailer.rb, app/views/comment_mailer, and test files.

Edit the Mailer

Similar to a controller, a mailer has methods called “actions," its instance variables are available in the email views, and it creates messages that are emailed to a recipient—similar to how a controller generates HTML to be sent back to the client. In app/mailers/comment_mailer.rb, use the default hash default :from 'example@gmail.com' to set the email address that will generate an email notification when a visitor leaves a comment.

Add a method inside the CommentMailer class that describes the action taking place—something like “comment_notification." Call the mail method and pass it hash arguments in the form of common email headers. The only hash headers truly required are to:, for declaring the email address that will receive the email notifications (this should be different than the :from address), and subject:, but there are other options available such as cc: and bcc:.

class CommentMailer < ApplicationMailer
    default from: 'example@gmail.com'

    def comment_notification
        mail(to: 'another_email_address@gmail.com', subject: 'New Blog Comment')
    end
end

Send Email When a Comment is Saved

To trigger the Action Mailer email notification, put a conditional statement in the create action in app/controllers/comments_controller. It calls the comment_notification method on the CommentMailer class only when a comment is saved. You can also pass arguments such as @article and @comment to make them available in the email view.

def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.new(comments_params)
    if @comment.save
        CommentMailer.comment_notification(@comment, @article).deliver
        flash[:success] = "Thanks for commenting!"
        redirect_to article_path(@article)
    else
        flash[:danger] = "All fields must be filled in to post a comment."
        redirect_to article_path(@article)
    end
end

Add Arguments to the Mailer Class Method

To make the @article and @comment instance variables available in the view, add arguments to the comment_notification method in app/mailers/comment_mailer.rb and set the arguments to instance variables.

def comment_notification(comment, article)
    @comment = comment
    @article = article 
    mail(to: 'example@gmail.com', subject: 'Blog Comment Recorded')
end

Create an Action Mailer View

For the email view, create a file in app/views/comment_mailer/ and name it comment_notification.html.erb, ensuring the name matches the Mailer class method created earlier. Build out the email template with any HTML or ERB you like, but the one I use is as simple as this:

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <p>Ryan, there is a new comment on the post:</p> 
    <p><h3><%= @article.title %></h3></p>
    <p><strong><%= @comment.name %></strong> wrote:</p>
    <p> "<%= @comment.body %>"</p>
  </body>
</html>

When Action Mailer sends a comment-notification email, the template I created renders the title of the article the visitor commented on, the commenter's name, and their entire comment. Pretty slick!

Setup Gmail for Sending Emails

The final steps are to make sure Gmail settings are setup properly in both development and production environments. In development, assuming you are using WEBrick and localhost:3000, place these lines in config/environments/development.rb to test Action Mailer.

config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
    address: "smtp.gmail.com",
    port: "587",
    domain: "gmail.com",
    authentication: "plain",
    enable_starttls_auto: true,  
    user_name: ENV["GMAIL_USERNAME"],
    password: ENV["GMAIL_PASSWORD"]
}

The “user_name" and “password" keys are for the Gmail account I am sending emails from. I use the Figaro gem for the ENV["GMAIL_USERNAME"] and ENV["GMAIL_PASSWORD"]values to prevent my Gmail username and password from being pushed to Github. There are other ways to do this but I think the Figaro gem is easier to use. The Figaro documentation is great if you wan to use it too.

I deploy my blog via Heroku and these are the settings I use in config/enviroments/production.rb:

config.active_record.dump_schema_after_migration = false
  config.action_mailer.perform_deliveries = true
  config.action_mailer.raise_delivery_errors = false
  config.action_mailer.default_url_options = { :host => 'www.your_app.com' }
  config.action_mailer.default :charset => "utf-8"
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address: "smtp.gmail.com",
    port: "587",
    domain: "gmail.com",
    authentication: "plain",
    enable_starttls_auto: true,  
    user_name: ENV["GMAIL_USERNAME"],
    password: ENV["GMAIL_PASSWORD"]
  }

Conclusion

With this code in place, you will no longer have to check your blog to see if people are commenting and interacting with your posts. It's a great way to get instant feedback on your writing and connect with people who share the same interests.