Ruby On Rails, Design, Simplicity, Web 2.0, Ajax, Mac and Tons of Pizza.

Oct 02

HowTo: track the effects of your email campaign

Posted by Sandro Paganotti in Ruby on Rails - comments are closed digg this add to delicious

When it’s time to send an email to all of your subscribers we always need to maximize the information we can get back from our campaign. Here are a few tricks that can help us in this operation:

Step one: the receivers list

First of all we need to set-up a table containing the list of the users; to do this we can use an existing table in our application or set up a new one; we’re going to follow this way and create it among with a new rails application.


rails campaign
cd campaign
ruby script/generate scaffold_resource user name:string email:string verification_hash:string
.. set up your database.yml ...
rake db:migrate
ruby script/server

As you may can notice I’ve created a table with just the fields we’re going to use in this how-to, but you can add as much user information as you want.

Before continue we need to hide the ‘verification_hash’ fields from our scaffold views; this is beacuse we’re going to create an ‘after_save’ filter that fills the verification_hash automatically; here’s the filter:


# inside app/models/user.rb
before_save :create_verification_hash

private

def create_verification_hash
    unless self.verification_hash.nil?
       self.verification_hash = Digest::SHA1.hexdigest("--" + rand(10) + "--" + name + Time.now.to_s "--") 
    end 
end

# inside config/environment.rb
require 'digest/sha1'


After you have created the users list you can start fill it with the receivers. You can do it by using the rails scaffold we have created in the code list above (http://localhost:3000/users) or you can use a SQL import command or wathever you like.

Then it’s time to set up ActionMailer, to do this you have to write a few configuration lines in your environment.rb; you could user either a smtp server or sendmail, for more information on how to complete the configuration please follow the wiki article on ActionMailer ; when you’re done you can run the following command:


     ruby script/generate mailer email

And create the app’s mail handler.

Step two: track the contents

We’re going to create a table called ‘contents’ that will contains all the url of our emails; we don’t need a scaffold ‘cause we’re not going to fill this table by hand but we’ll create an helper that will ‘catch’ all the urls in an email template and adds them to our table.

Next we need to create a table that links contents and users; I’ve called that ‘mail_checks’ but maybe there are better names; in this table we’re going to store all the clicks the users make on the contents.


ruby script/generate model content
ruby script/generate model mail_check

Now we need to open ‘002_create_contents.rb’ and write:


class CreateContents < ActiveRecord::Migration
  def self.up
    create_table :contents do |t|
      t.column :url, :string
      t.column :verification_hash, :string
      t.column :campaign_code, :string
    end
  end

  def self.down
    drop_table :contents
  end
end

In ‘003_create_mail_checks.rb’ we have to write:


class CreateMailChecks < ActiveRecord::Migration
  def self.up
    create_table :mail_checks do |t|
      t.column :contact_id, :integer
      t.column :content, :string
      t.column :created_on, :datetime
    end
  end

  def self.down
    drop_table :mail_checks
  end
end

And then migrate: (remeber also to add ‘has_many’ and ‘belongs_to’ to the models according the filelds created)

rake db:migrate

We need to repeat the same ‘before_save’ filter inside ‘models/content.rb’ in order to let the istances of the Content model fill their verification_hash; when done we can continue to the next chapter.

Step three: the e-mail

What we’re looking for is a rake task that lets you specify the name of the e-mail you want to send, the subject and the sender, to do this first we need to create a structure that let us handle multiple e-mails without creating a method in our ActionMailer class for each of them:


# inside models/email.rb
class Email < ActionMailer::Base

  helper :application

  Dir.glob(File.join(RAILS_ROOT,"app","views","email","*.rhtml")).collect{|a| a.split("/").last.split(".").first}.each do |e|
    define_method(e) do |sender,email,sbj,dbcontact|
      recipients email
      from  sender
      subject sbj

      # Email body substitutions go here
      body  (  :dbcontact => dbcontact )

    end
  end

end

As you may noticed I’ve included the ‘application._helper.rb’ in this ActionMailer; by doing this I can now use all the helpers in that file inside my email views; in detail I can create a set of helpers to parse and store the urls contained in the .rhtml template:


# inside app/helpers/application_helper.rb 

   def url_for_mail(url)
    if Content.find_by_url(url).nil?
      savedurl = Content.create(:url=>url) 
    else
      savedurl= Content.find_by_url(url)
    end
    url_for(  :controller=>"campaign", 
              :action=>"redirect",  
              :content_verification_hash => savedurl.verification_hash,
              :verification_hash => @dbcontact.verification_hash,
              :host => // HERE YOUR APPLICATION HOST //,
              :only_path => false
           )
  end

We’re almost done: three things remain:
  • Modify the email template in order to use this helper while generating urls,
  • Create a rake task to send an email,
  • Create the redirect action.

Step four: final adjustements

Now we can create our first email message with this rules:
  • Use @dbcontact.name instead of the name of the receiver (this rule must be extended to all the attributes of our contacts)
  • Use ‘url()’ helper ( http://someurl.com —> url(‘http://someurl.com’) )

You can find the rake task here and it must be put inside the lib/tasks directory of our campaign application, you can invoke it with this command:


rake campaign:send SENDER=info@myowndomain.com SUBJECT="Monthly newsletter" MAILNAME="you_rhtml_email_name" 

Last but not least we need to create a controller called campaign and an action called redirect:


# inside app/controllers/campaing_controller.rb
  def redirect
    @user = Contact.find_by_verification_hash(params[:verification_hash]) 
    @content = Content.find_by_verification_hash(params[:content_verification_hash]) 
    if @user.nil? or @content.nil?
      render :text=>"Redirect not allowed" 
      return
    else
      @user.mail_checks.create(
        :content => @content.url
      )
      redirect_to @content.url 
      return
    end
    redirect_to // PUT A DEFAULT REDIRECT URL HERE
  end

# inside config/routes.rb

  map.connect 'vc/:verification_hash/:content_verification_hash', :controller => 'campaign', :action=>'redirect'


Ok, now you’re reday to start your first 100% tracked e-mail campaign, each time a user clicks on a link inside your e-mail it will be stored inside the ‘mail_checks’ table; a few final considerations:
  • Using a SHA – Digest as ‘verification_hash’ is a secure but not-very-nice-looking way, a better solution could be use a more small self-generate digest.
  • You can add as many report as you want by querying the mail_checks table.

Hope you like this tutorial.
Sandro.

Post a comment

Categories:

Tags:

Powered by Mephisto, Valid XHTML 1.1, Valid CSS - Supported by Wave Factory