Tracking Email Open in Rails

In this article, we will implement a simple tracking of email opens sent to a prospect. I had to build this tool for my own use to find unmet needs in small businesses. Let's first generate the model to track the email opens.

rails generate model EmailOpen email ip

Define the tracking endpoint in routes.rb:

get '/beacon' => 'tracking#beacon'

Download transparent beacon image from 1x1px and save it in public folder as beacon.png. In the email template, ask_question.html.erb, provide a link to the beacon.png.

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
        Body of email goes here...
        <img src="<%= email_tracker_url(@email) %>" >
  </body>
</html>

The tracking helper encodes the email and appends it to the URL.

module TrackingHelper
  def email_tracker_url(email)
    "https://example.com/beacon?data=#{Base64.encode64(email)}"
  end
end

When the user opens this email, it will hit the tracking endpoint.

class TrackingController < ApplicationController
  def beacon
    email = Base64.decode64(params[:data]) 

    EmailOpen.find_or_create_by(email: email) do |e|
      e.ip = request.ip
    end
    send_file 'public/beacon.png', type: 'image/png'
  end
end

We are using find_or_create_by to avoid creating multiple records for the same user. We don't want to create a record when the user replies to our email (by opening the same email later). We send the 1x1 transparent image back to the email client. Alternative to having an image in the file system (based on email_engine source code):

send_data Base64.decode64("R0lGODlhAQABAPAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="), type: "image/gif", disposition: "inline"

We can test this functionality from the rails console.

email_template = EmailTemplate.first
Struct.new("Prospect", :email)
prospect = Struct::Prospect.new("bugs@disney.com")
OutreachMailer.ask_question(prospect, email_template).deliver_now

The mailer is similar to any ActionMailer class that sends an email. The solution in this article is customized for my application requirements. The link in the reference section handles the case where the user might be logged in to your webapp.

References


Related Articles