Chapter 9. Action Mailer

Even if we mainly use Ruby on Rails to generate web pages, it sometimes is useful to be able to send an e-mail.
So let's go and build an example with minimal user management for a web shop that automatically sends an e-mail to the user when a new user is created:
$ rails new webshop
  [...]
$ cd webshop 
$ rails generate scaffold User name email
  [...]
$ rake db:migrate
  [...]
$
For the user model we create a minimal validation in the app/models/user.rb, so that we can be sure that each user has a name and a syntactically correct e-mail address.
class User < ActiveRecord::Base
  validates :name,
            presence: true

  validates :email,
            presence: true,
            format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
end
There is a generator with the name mailer that creates the files required for mailing. First, we have a look at the output of the rails generate mailer, without passing any further arguments:
$ rails generate mailer
Usage:
  rails generate mailer NAME [method method] [options]

Options:
      [--skip-namespace]        # Skip namespace (affects only isolated applications)
  -e, [--template-engine=NAME]  # Template engine to be invoked
                                # Default: erb
  -t, [--test-framework=NAME]   # Test framework to be invoked
                                # Default: test_unit

Runtime options:
  -f, [--force]    # Overwrite files that already exist
  -p, [--pretend]  # Run but do not make any changes
  -q, [--quiet]    # Suppress status output
  -s, [--skip]     # Skip files that already exist

Description:
============
    Stubs out a new mailer and its views. Passes the mailer name, either
    CamelCased or under_scored, and an optional list of emails as arguments.

    This generates a mailer class in app/mailers and invokes your template
    engine and test framework generators.

Example:
========
    rails generate mailer Notifications signup forgot_password invoice

    creates a Notifications mailer class, views, and test:
        Mailer:     app/mailers/notifications.rb
        Views:      app/views/notifications/signup.text.erb [...]
        Test:       test/mailers/notifications_test.rb

$
That is just what we are expecting. So let's now create the mailer notification:
$ rails generate mailer Notification
      create  app/mailers/notification.rb
      invoke  erb
      create    app/views/notification
      invoke  test_unit
      create    test/mailers/notification_test.rb
$ 
In the file app/mailers/notification.rb you will find the controller:
class Notification < ActionMailer::Base
  default from: "from@example.com"
end
In it, we create a method new_account(user), with which we send the confirmation e-mail for a new account:
class Notification < ActionMailer::Base
  default from: "from@example.com"

  def new_account(user)
    @user = user
    mail(to: user.email,
         subject: "The account #{user.name} is active.")
  end
end
Now we create the view for this method. The file name app/views/notification/new_account.text.erb is composed from the method name and the ending text.erb.
Hello <%= @user.name %>,

your new account is active.

Have a great day!
  A Robot
As we want to send this e-mail afer the create of a User, we still need add an after_create callback which triggers the delivery. That is done in app/models/user.rb:
class User < ActiveRecord::Base
  validates :name,
            presence: true

  validates :email,
            presence: true,
            format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }

  after_create :send_welcome_email
    
  private
      
  def send_welcome_email
    Notification.new_account(self).deliver
  end
end
Let's create a new User in the console:
$ rails console
Loading development environment (Rails 4.0.0)
>> User.create(name: 'Wintermeyer', email: 'stefan.wintermeyer@amooma.de')
   (0.1ms)  begin transaction
  SQL (4.1ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Wed, 17 Jul 2013 17:12:19 UTC +00:00], ["email", "stefan.wintermeyer@amooma.de"], ["name", "Wintermeyer"], ["updated_at", Wed, 17 Jul 2013 17:12:19 UTC +00:00]]
  Rendered notification/new_account.text.erb (0.8ms)

Sent mail to stefan.wintermeyer@amooma.de (11.1ms)
Date: Wed, 17 Jul 2013 19:12:20 +0200
From: from@example.com
To: stefan.wintermeyer@amooma.de
Message-ID: <51e6d07411000_a49d3fd87c8606d457513@SW.local.mail>
Subject: The account Wintermeyer is active.
Mime-Version: 1.0
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

Hello Wintermeyer,

your new account is active.

Have a great day!
  A Robot

   (2.9ms)  commit transaction
=> #<User id: 1, name: "Wintermeyer", email: "stefan.wintermeyer@amooma.de", created_at: "2013-07-17 17:12:19", updated_at: "2013-07-17 17:12:19">
>> exit
$
That was straightforward. In the development mode we see the e-mail in the log. In production mode it would be send to the configured SMTP gateway.

Thank you for your support and the visibility by linking to this website on Twitter and Facebook. That helps a lot!