Test Your Mailers


Introduction

You should really test those emails that are being sent out to your clients. Something I think most developers miss doing. They send the email as the test and call it a day. But you can test your emails pretty easily.

Since I’m a RSpec fan. I will go through a couple of examples and even how to test one from Devise.

Starting off.

In Rails there a couple of configurations that you have to setup. I won’t go over those because that part is plastered all over the net. For these examples though there is a UserMailer class that has some custom methods.

#app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base

  default content_type: 'multipart/alternative',
          parts_order: [ "text/html", "text/enriched", "text/plain", "application/pdf" ],
          from: 'noreply@willywos.github.io' #not a real domain

  # User is my default user object, doesn't really have much in it.
  # AccountName is just a string field that contains..umm 'Test Account'
  def send_welcome_mail(user, account_name)
    @user         = user
    @account_name = account_name
    mail(:to => @user.email, :subject => "#{@account_name}: Welcome!" )
  end
end

This class is pretty easy and small. It has one method called send_welcome_mail that takes two arguments. User which is just a rails model of a user object that has a couple of methods on it and the last argument is account_name. Which is just a string field.

Normally you would call it like:

  UserMailer.send_welcome_mail(user, 'Test Account').deliver

The view has some text in it also:

#/app/views/user_mailer/send_welcome_mail.html.erb

<p>Hello <%= @user.full_name %>,</p>
<p>Welcome To <%= @account_name %>!</p>
<p>You are now a member of <%= @account_name %>. Please login to start accessing your account. </p>
<p><a href="http://willywos.github.io/users/welcome">Click Here to Login</a></p>

<p>Thank you,</p>
<p><%= @account_name %> Administrator</p>

Now this is where you would go run off and do a little testing and make sure the email is sent out and formatted correctly. Then call it a day after you had everything working.

###Spec It! Spec It! Spec It!

#spec/mailers/user_mailer/send_welcome_mail_spec.rb
require 'rails_helper'

describe UserMailer do
  describe 'Send Welcome Mail' do
    let(:user) { FactoryGirl.build(:user, email: 'test@willywos.github.io', firstName: 'Mail', lastName:'Master') }
    let(:mail) { UserMailer.send_welcome_mail(user, 'Connection-Test') }

    it 'renders the subject' do
      expect(mail.subject).to eql('Test Account: Welcome!')
    end

    it 'renders the receiver email' do
      expect(mail.to).to eql(['test@willywos.github.io'])
    end

    it 'renders the sender email' do
      expect(mail.from).to eql(["noreply@willywos.github.io"])
    end

    it 'assigns @user full_name' do
      expect(mail.body.encoded).to match('Mail Master')
    end

    it 'assigns @account_name' do
      expect(mail.body.encoded).to match('Test Account')
    end
  end
end

You can see that from the test above. It’s pretty easy.

Testing the subject:

it 'renders the subject' do
  expect(mail.subject).to eql('Test Account: Welcome!')
end

You can even test the message body and make sure your text is showing correctly and even the formatting.

it 'assigns @account_name' do
  expect(mail.body.encoded).to match('You are now a member of Test Account. Please login to start accessing your account.')
end

###Devise

So lots of people including myself use Devise for our authentication layer. It’s very easy and the code on GitHub is very excellent to study and learn new things.

I found the easiest way to do this was to setup a custom mailer.

#config/initializers/devise.rb
Devise.setup do |config|
  # Configure the class responsible to send e-mails.
  config.mailer = 'DeviseMailer'
end
#app/mailers/devise_mailer.rb
class DeviseMailer < Devise::Mailer
  helper :application # gives access to all helpers defined within `application_helper`.
  include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`

  def reset_password_instructions(record, token, opts={})
    @account     = record.account_name
    @resource    = record
    mail         = super
    mail.from    = "\"#{@account} Admin\" <admin@willywos.github.io>"
    mail.subject = "#{@account}: Reset Password Instructions"
    mail
  end

  def confirmation_instructions(record, token, opts={})
    @account     = record.account_name
    mail         = super
    mail.from    = "\"#{@account} Admin\" <admin@willywos.github.io>"
    mail.subject = "#{@account}: Confirm your account instructions"
    mail
  end

  def unlock_instructions(record, token, opts={})
    @account     = record.account_name
    mail         = super
    mail.from    = "\"#{@account} Admin\" <admin@willywos.github.io>"
    mail.subject = "#{@account}: Unlock your account instructions"
    mail
  end
end

You have to move the mailer views out of the devise folder and into a new one called devise_mailer.

###Spec It! Spec It! Spec It!

#spec/mailers/devise_mailer/reset_password_instructions_spec.rb
require 'rails_helper'

describe DeviseMailer do
  describe 'Send Password Reset Mail' do
    let(:user) { FactoryGirl.build(:user, email: 'test@willywos.github.io', firstName: 'Mail', lastName:'Master') }
    let(:mail) { DeviseMailer.reset_password_instructions(user, '12345-678-910', {}) }

    before(:each) do
      allow(user).to receive(:account_name).and_return('Test Account')
    end

    it 'renders the subject' do
      expect(mail.subject).to eql('Test Account: Reset Password Instructions')
    end

    it 'renders the receiver email' do
       expect(mail.to).to eql(['test@willywos.github.io'])
    end

    it 'renders the sender email' do
      expect(mail.from).to eql(["admin@willywos.github.io"])
    end
  end
end

That should be all you have to do. If you notice that your Devise mails are blank make sure that the views are in the correct folder.

Conclusion

Mails are important. As developers, I think we consider them to be less important as the main application. It’s client facing though and it’s nice that these can be easily tested to make sure that the content of the message and things like subject and from address are correctly done.

The End