-
Notifications
You must be signed in to change notification settings - Fork 0
Backend Training: Mandrill Mailer
In this section, we will go over on how to setup mailers to send out emails when a user subscribes or submits the contact us form.
First, let's include the mandrill-api
gem in our Gemfile.
# Gemfile
.....
# Mailchimp Mailer
gem 'mandrill-api'
group :development, :test do
.....
end
.....
Install the gem
$ bundle install
For development, we would like to user letter_opener
to open the mail instead of receiving real emails.
# config/environments/development.rb
Rails.application.configure do
......
# Don't care if the mailer can't send.
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_caching = false
config.action_mailer.delivery_method = :letter_opener
......
end
Next, create a base mandrill mailer file inside app/mailers/
# app/mailers/mandrill_mailer.rb
require 'mandrill'
# Base Mandrill API Connection
class MandrillMailer < ApplicationMailer
include Rails.application.routes.url_helpers
include ActionView::Helpers::UrlHelper
private
def send_mail(email, subject, body)
mail(to: email, subject: subject, body: body, content_type: 'text/html')
end
def mandrill_template(template_name, attributes)
mandrill = Mandrill::API.new(ENV['MANDRILL_SMTP_API_KEY'])
merge_vars =
attributes.map do |key, value|
{ name: key, content: value }
end
mandrill.templates.render(template_name, [], merge_vars)['html']
end
end
And update the application_mailer
with some basic configs
# app/mailers/application_mailer.rb
# Application Mailer
class ApplicationMailer < ActionMailer::Base
layout 'mailer'
default(
from: ENV['SMTP_NOTIFICATION_EMAIL'],
reply_to: ENV['SMTP_NOTIFICATION_EMAIL']
)
end
Great! We have our base mailer setup now let's create a mailer for the contact form.
# Contact Mailer
class ContactMailer < MandrillMailer
def notify_admin(contact)
@contact = contact.reload
subject = 'Contact Submission'
body = mandrill_template(
ENV['MANDRILL_CONTACT_SUBMISSION_TEMPLATE'],
'TABLE' => table
)
email_to = ENV['MANDRILL_SMTP_NOTIFICATION_EMAIL']
send_mail(email_to, subject, body)
end
private
def table
render_to_string(
partial: 'mailers/table',
locals: {
resource: @contact,
fields: %w[name email message created_at]
},
layout: false
)
end
end
Next, let's setup the environment variables...
# .env
SMTP_NOTIFICATION_EMAIL='[email protected]'
MANDRILL_SMTP_API_KEY='vLGYnebipCsaycGSTAfGew'
MANDRILL_SMTP_USER_NAME='[email protected]'
MANDRILL_SMTP_DOMAIN='cleverbanana.com'
MANDRILL_SMTP_NOTIFICATION_EMAIL='[email protected]'
MANDRILL_CONTACT_SUBMISSION_TEMPLATE='cb_web-general'
Now, let's add a generic view for our emails.
# app/views/mailers/_body.slim
table[style="width: 100%; border-collapse: collapse; border: 1px solid #eee; text-align: left;"]
thead
tr[style="background: #ffb600; color: white;"]
th[style="white-space:nowrap; padding: 10px 15px;"] FIELD
th[style="padding: 10px 15px;"] VALUE
tbody
- fields.each do |field|
tr[style="border-bottom: 1px solid #eee;"]
td[style="white-space:nowrap; padding: 10px 15px;"]= field.humanize
td[style="padding: 10px 15px;"]= resource.send(field.to_sym)
Now, the mailer is ready, let's hook it up with the contact model. We want to receive mail only if the contact is created successfully.
# app/models/contact.rb
class Contact < ApplicationRecord
after_create :notify_admin
......
private
def notify_admin
ContactMailer.notify_admin(self).deliver_now
end
end
Now, submit the contact form and you should see...
Great! it worked. Now let's add mailer for the subscriber form as well.
# app/mailers/subscriber_mailer.rb
# Subscriber Mailer
class SubscriberMailer < MandrillMailer
def notify_admin(subscriber)
@subscriber = subscriber
subject = 'New Subscriber'
body = mandrill_template(
ENV['MANDRILL_CONTACT_SUBMISSION_TEMPLATE'],
'TABLE' => table
)
email_to = ENV['MANDRILL_SMTP_NOTIFICATION_EMAIL']
send_mail(email_to, subject, body)
end
private
def table
render_to_string(
partial: 'mailers/table',
locals: {
resource: @subscriber,
fields: %w[email]
},
layout: false
)
end
end
p.s. here we have removed the created_at because subscriber is not stored in the database and hence don't have a created_at date.
# app/models/subscriber.rb
class Subscriber
.....
def create
return false unless valid?
notify_admin
end
.....
private
def notify_admin
SubscriberMailer.notify_admin(self).deliver_now
end
.....
end
Now, go to your subscriber form and submit, and you should see...
Now, let's add specs to validate these mailers are called
# spec/models/subscriber_spec.rb
require 'rails_helper'
RSpec.describe Subscriber, type: :model do
......
describe 'Callbacks' do
let(:subject) { build(:subscriber) }
it 'should send mail' do
expect(subject).to receive(:notify_admin)
subject.save
end
end
end
and
# spec/models/contact_spec.rb
require 'rails_helper'
RSpec.describe Contact, type: :model do
......
describe 'Callbacks' do
let(:subject) { build(:contact) }
it 'should send mail to admin' do
expect(subject).to receive(:notify_admin)
subject.save
end
end
end
Now, run the specs.
$ rspec spec
.............................**...........*.....................................
Pending: (Failures listed here are expected and do not affect your suite's status)
1) ContactDecorator add some examples to (or delete) /Users/ilunglee/Work/rails/mock_project/spec/decorators/contact_decorator_spec.rb
# Not yet implemented
# ./spec/decorators/contact_decorator_spec.rb:4
2) FaqDecorator add some examples to (or delete) /Users/ilunglee/Work/rails/mock_project/spec/decorators/faq_decorator_spec.rb
# Not yet implemented
# ./spec/decorators/faq_decorator_spec.rb:4
3) AdminUser add some examples to (or delete) /Users/ilunglee/Work/rails/mock_project/spec/models/admin_user_spec.rb
# Not yet implemented
# ./spec/models/admin_user_spec.rb:4
Finished in 5.16 seconds (files took 5.96 seconds to load)
80 examples, 0 failures, 3 pending
Great! It passes. Let's commit and move on.
$ git add -A
$ git commit -m 'Mandrill Mailer'