📮 Email analytics for Rails
You get:
- A history of emails sent to each user
- Easy UTM tagging
- Optional open and click tracking
Ahoy Email 1.0 was recently released! See how to upgrade
🚄 To manage unsubscribes, check out Mailkick
🔥 To track visits and events, check out Ahoy
Add this line to your application’s Gemfile:
gem 'ahoy_email'
And run the generator. This creates a model to store messages.
rails generate ahoy_email:install
rails db:migrate
Ahoy creates an Ahoy::Message
record for each email sent by default. You can disable history for a mailer:
class CouponMailer < ApplicationMailer
track message: false # use only/except to limit actions
end
Or by default:
AhoyEmail.default_options[:message] = false
Ahoy records the user a message is sent to - not just the email address. This gives you a full history of messages for each user, even if he or she changes addresses.
By default, Ahoy tries @user
then params[:user]
then User.find_by(email: message.to.first)
to find the user.
You can pass a specific user with:
class CouponMailer < ApplicationMailer
track user: -> { params[:some_user] }
end
The user association is polymorphic, so use it with any model.
To get all messages sent to a user, add an association:
class User < ApplicationRecord
has_many :messages, class_name: "Ahoy::Message", as: :user
end
And run:
user.messages
Record extra attributes on the Ahoy::Message
model.
Create a migration to add extra attributes to the ahoy_messages
table. For example:
class AddCouponIdToAhoyMessages < ActiveRecord::Migration[5.2]
def change
add_column :ahoy_messages, :coupon_id, :integer
end
end
Then use:
class CouponMailer < ApplicationMailer
track extra: {coupon_id: 1}
end
You can use a proc as well.
class CouponMailer < ApplicationMailer
track extra: -> { {coupon_id: params[:coupon].id} }
end
Automatically add UTM parameters to links.
class CouponMailer < ApplicationMailer
track utm_params: true # use only/except to limit actions
end
The defaults are:
utm_medium
-email
utm_source
- the mailer name likecoupon_mailer
utm_campaign
- the mailer action likeoffer
You can customize them with:
class CouponMailer < ApplicationMailer
track utm_params: true, utm_campaign: -> { "coupon#{params[:coupon].id}" }
end
Skip specific links with:
<%= link_to "Go", some_url, data: {skip_utm_params: true} %>
You can track opens with Google Analytics without the need for web endpoints and local storage with the additional configuration below.
Add a GA tracking code to your ahoy_email.rb
initializer:
AhoyEmail.default_options[:google_analytics_code] = 'UA-something-here-N'
Create a migration with:
class AddTokenToAhoyMessages < ActiveRecord::Migration[5.2]
def change
add_column :ahoy_messages, :token, :string
add_column :ahoy_messages, :opened_at, :timestamp
add_column :ahoy_messages, :clicked_at, :timestamp
add_index :ahoy_messages, :token
end
end
Create an initializer config/initializers/ahoy_email.rb
with:
AhoyEmail.api = true
And add to mailers you want to track:
class CouponMailer < ApplicationMailer
track open: true, click: true # use only/except to limit actions
end
For opens, an invisible pixel is added right before the </body>
tag in HTML emails. If the recipient has images enabled in their email client, the pixel is loaded and the open time recorded.
For clicks, a redirect is added to links to track clicks in HTML emails.
https://chartkick.com
becomes
https://yoursite.com/ahoy/messages/rAnDoMtOkEn/click?url=https%3A%2F%2Fchartkick.com&signature=...
A signature is added to prevent open redirects.
Skip specific links with:
<%= link_to "Go", some_url, data: {skip_click: true} %>
By default, unsubscribe links are excluded. To change this, use:
AhoyEmail.default_options[:unsubscribe_links] = true
You can specify the domain to use with:
AhoyEmail.default_options[:url_options] = {host: "mydomain.com"}
Subscribe to open and click events by adding to the initializer:
class EmailSubscriber
def open(event)
# your code
end
def click(event)
# your code
end
end
AhoyEmail.subscribers << EmailSubscriber.new
Here’s an example if you use Ahoy to track visits and events:
class EmailSubscriber
def open(event)
event[:controller].ahoy.track "Email opened", message_id: event[:message].id
end
def click(event)
event[:controller].ahoy.track "Email clicked", message_id: event[:message].id, url: event[:url]
end
end
AhoyEmail.subscribers << EmailSubscriber.new
Set global options
AhoyEmail.default_options[:user] = -> { params[:admin] }
Use a different model
AhoyEmail.message_model = -> { UserMessage }
Or fully customize how messages are tracked
AhoyEmail.track_method = lambda do |data|
# your code
end
If you prefer to use Mongoid instead of ActiveRecord, create app/models/ahoy/message.rb
with:
class Ahoy::Message
include Mongoid::Document
belongs_to :user, polymorphic: true, optional: true, index: true
field :to, type: String
field :mailer, type: String
field :subject, type: String
field :sent_at, type: Time
end
Breaking changes
-
UTM tagging, open tracking, and click tracking are no longer enabled by default. To enable, create an initializer with:
AhoyEmail.api = true AhoyEmail.default_options[:open] = true AhoyEmail.default_options[:click] = true AhoyEmail.default_options[:utm_params] = true
-
Only sent emails are recorded
-
Proc options are now executed in the context of the mailer and take no arguments
# old user: ->(mailer, message) { User.find_by(email: message.to.first) } # new user: -> { User.find_by(email: message.to.first) }
-
Invalid options now throw an
ArgumentError
-
AhoyEmail.track
was removed in favor ofAhoyEmail.default_options
-
The
heuristic_parse
option was removed and is now the default
View the changelog
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features