First off let me say that I am new to
Ruby and Rails development so my comments probably won't impress any
Sr. developers or win any followers among Ruby Purists. However, my
intent is to share actual learning by someone new to Ruby and
hopefully help some other newbies in the process.
This post is about integrating my rails
application with Mandrill for the purpose of sending transactional
e-mail messages. So, let's get started.
My objective is to have three modes of
operation in sending my mail messages.
- Test – this mode will call my send mail functions, but not invoke the Mandrill APIs. I will simulate various responses by hard-coding them into the results of my mail methods instead of getting them from Mandrill.
- Development – in this mode, my send mail functions will call the Mandrill APIs, but using Mandrill's test mode. This will allow me to verify that my JSON calls are in fact getting to Mandrill and able to return their result codes.
- Production – this mode will only be used on the production server and will of course, deliver my messages to their intended recipient.
Getting started with Mandrill was easy.
I just signed up for a free account. After signing in I navigated
to the Configuration Menu (the Gear) and selected SMTP & API
credentials. We need a key from Mandrill to include in all of our
API calls and this is where we create them. Click the “+ New API
Key” button. Which takes us here:
I created two keys, one named TestKey
for which I selected the Test Key check box, and one named Production
for which I did not select Test Key.
I'm going to use two layers of
configuration in my Rails app to set up my Mandrill email access.
The first is in my project/config/local_env.yml file. This
file holds what I think of as global constants that I don't want
stored up on Github. The file can be added to your
project/.gitignore file and won't be stored in your
repository. I set up two constants to contain my keys:
MANDRILL_PROD_API_KEY:
“TheFunkyStringMandrillMade”
MANDRILL_TEST_API_KEY:
“AnotherFunkeyStringMandrillMade”
Each key was actually 22 mixed case
letters and numbers.
While I was in the local_env.yml file I
also threw in a couple of other constants that I might want to change
latter that are email related, the name and address of the person I
want my emails to be from.
OWNER_EMAIL: “myname@mydomain.com”
OWNER_NAME: “My Name”
Now I need to reference these values in
my application. This is where the project/config/environments folder
comes into play. It contains three files that are loaded into your
application at run time based upon the mode you are actually running
in:
development.rb
production.rb
test.rb
I created four configuration variables
in each of the three files:
config.mandrillsend = false
config.mandrillkey =
ENV["MANDRILL_TEST_API_KEY"]
config.returnaddress =
ENV["OWNER_EMAIL"]
config.returnname = ENV["OWNER_NAME"]
The first one is how I intend to
implement my code that skips the API calls completely. I'll set it
to false when I'm in hard core development mode and don't want to
even make the calls to Mandrill, and I'll set it to true when I want
the calls made. It will generally be true in Development and
Production modes, but false in test mode. Also, in the test.rb and
developmen.rb files I set
config.mandrillkey =
ENV["MANDRILL_TEST_API_KEY"]
and as you can guess, in production.rb
I set
config.mandrillkey =
ENV["MANDRILL_PROD_API_KEY"]
The next step was to build a function
that I could call to actually send a message to Mandrill's APIs. I
created:
project/lib/mandrill.rb
Keep in mind that when you put code in
the project/lib folder it isn't reloaded on each invocation
like your models, views and controllers so when I was debugging I had
to stop and start the rails server after each change. Here is the
complete file:
module Mandrill
# This object is actually returned
from the sendtemplate function
# instead of a real result when I set
config.mandrillsend = false.
# I can change it to simulate various
results.
class FakeRes
def code
"200"
end
def body
"Test mode"
end
end
class Mandrill
require "net/http"
require "uri"
# Here I create a dummy JSON record
that is ready to hold all the parameters to send
# in an API call. I do this just
to help me visualize the record. You could skip this and just
# build up the record from scratch
when you call sendtemplate.
def initialize
@jhash = {
"key" =>
Rails.configuration.mandrillkey,
"template_name" =>
"no-template",
"template_content" =>
[{
"name" =>
"NotNeeded",
"content" =>
"NotSupplied"
}],
"message" => {
"from_email" =>
Rails.configuration.returnaddress,
"from_name" =>
Rails.configuration.returnname,
"to" => [{
"email" =>
Rails.configuration.returnaddress,
"name" =>
Rails.configuration.returnname,
"type" => "to"
}],
"headers" => {
"Reply-To" =>
Rails.configuration.returnaddress
},
"subject" =>
"Getting started",
"important" =>
false,
"track_opens" =>
nil,
"track_clicks" =>
nil,
"auto_text" =>
nil,
"auto_html" =>
nil,
"inline_css" =>
nil,
"url_strip_qs" =>
nil,
"preserve_recipients"
=> nil,
"view_content_link"
=> nil,
"bcc_address" =>
nil,
"tracking_domain"
=> nil,
"signing_domain" =>
nil,
"return_path_domain"
=> nil,
"merge" => true,
"global_merge_vars"
=> [
{
"name" =>
"CURRENT_YEAR",
"content" =>
"2014"
},
{
"name" =>
"LIST_COMPANY",
"content" =>
"My Company"
}
]
}, # message
"async" => false,
"ip_pool" => "Main
Pool"
} # jhash
end # initialize
def sendtemplate(template, from_email, from_name, to_email, to_name, subject, merge_vars, bcc ="")
Rails.logger.debug("Now invoking sendtemplate")
Rails.logger.debug(template, from_email, from_name, to_email, to_name, subject, bcc)
Rails.logger.debug(merge_vars.to_s)
if Rails.configuration.mandrillsend
Rails.logger.debug("Rails.configuration.mandrillsend set to true so trying to send email")
# Build an array of to values
if bcc == ""
@jhash["message"]["to"] = [{"email" => to_email,"name" => to_name,"type" => "to"}]
else
@jhash["message"]["to"] = [{"email" => to_email,"name" => to_name,"type" => "to"},
{"email" => bcc,"name" => bcc,"type" => "bcc"}]
end
@jhash.update("template_name" => template)
@jhash["message"].update("from_email" => from_email)
@jhash["message"].update("from_name" => from_name)
@jhash["message"]["headers"].update("Reply-To" => from_email)
@jhash["message"].update("subject" => subject)
@jhash["message"].update("global_merge_vars" => merge_vars)
service_url = "https://mandrillapp.com/api/1.0/messages/send-template.json"
Rails.logger.debug(service_url)
url = URI.parse(service_url)
headers = {"host" => url }
req = Net::HTTP::Post.new(url.path)
req["Content-Type"] = "application/json"
req["Accept"] = "application/json"
req.body = JSON.generate(@jhash)
Rails.logger.debug("Start ====req.body==========")
Rails.logger.debug(req.body)
Rails.logger.debug("End ======req.body==========")
con = Net::HTTP.new(url.host, url.port)
# ssl for https
con.use_ssl = true
con.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = con.start {|http| http.request(req) }
Rails.logger.debug(res.code)
Rails.logger.debug(res.body)
else
Rails.logger.debug("Rails.configuration.mandrillsend set to false so no email sent")
res = FakeRes.new
Rails.logger.debug(res)
end
Rails.logger.debug("Now done with SendTeamplate")
return res
end #sendtemplate
end #class Mandrill
end #module Mandrill
Now to send an email message I add
require “mandrill”
in my controller. Then it's just two
lines of code:
mandrillsend = Mandrill::Mandrill.new
result =
mandrillsend.sendtemplate(template, from_email, from_name, to_email,
to_name, subject, merge_vars, bcc_email)
So now you know, for better or for
worse, how I implemented Mandrill send-template in my Rails project.
In my next post I'll cover implementing the mail template and passing
the values into Mandrill to build up the message content.