/mailkick

Email subscriptions for Rails

Primary LanguageRubyMIT LicenseMIT

Mailkick

Email subscriptions for Rails

  • Add one-click unsubscribe links to your emails
  • Fetch bounces and spam reports from your email service

Mailkick 1.0 was recently released - see how to upgrade

đź“® Check out Ahoy Email for analytics

Build Status

Installation

Add this line to your application’s Gemfile:

gem "mailkick"

And run the generator. This creates a table to store subscriptions.

bundle install
rails generate mailkick:install
rails db:migrate

Getting Started

Add has_subscriptions to your user model:

class User < ApplicationRecord
  has_subscriptions
end

Subscribe to a list

user.subscribe("sales")

Unsubscribe from a list

user.unsubscribe("sales")

Check if subscribed

user.subscribed?("sales")

Get subscribers for a list (use this for sending emails)

User.subscribed("sales")

Unsubscribe Links

Add an unsubscribe link to your emails. For HTML emails, use:

<%= link_to "Unsubscribe", mailkick_unsubscribe_url(@user, "sales") %>

For text emails, use:

Unsubscribe: <%= mailkick_unsubscribe_url(@user, "sales") %>

When a user unsubscribes, they are taken to a mobile-friendly page and given the option to resubscribe. To customize the view, run:

rails generate mailkick:views

which copies the view into app/views/mailkick.

Bounces and Spam Reports

Fetch bounces, spam reports, and unsubscribes from your email service. Create config/initializers/mailkick.rb with a method to handle opt outs.

Mailkick.process_opt_outs_method = lambda do |opt_outs|
  emails = opt_outs.map { |v| v[:email] }
  subscribers = User.includes(:mailkick_subscriptions).where(email: emails).index_by(&:email)

  opt_outs.each do |opt_out|
    subscriber = subscribers[opt_out[:email]]
    next unless subscriber

    subscriber.mailkick_subscriptions.each do |subscription|
      subscription.destroy if subscription.created_at < opt_out[:time]
    end
  end
end

And run:

Mailkick.fetch_opt_outs

The following services are supported:

Will gladly accept pull requests for others.

AWS SES

Add the gem

gem "aws-sdk-sesv2"

And configure your AWS credentials. Requires ses:ListSuppressedDestinations permission.

If you started using Amazon SES before November 25, 2019, you have to manually enable account-level suppression list feature.

Mailchimp

Add the gem

gem "gibbon", ">= 2"

And set ENV["MAILCHIMP_API_KEY"] and ENV["MAILCHIMP_LIST_ID"].

Mailgun

Add the gem

gem "mailgun-ruby"

And set ENV["MAILGUN_API_KEY"].

Mandrill

Add the gem

gem "mandrill-api"

And set ENV["MANDRILL_APIKEY"].

Postmark

Add the gem

gem "postmark"

And set ENV["POSTMARK_API_KEY"].

SendGrid

Add the gem

gem "sendgrid-ruby"

And set ENV["SENDGRID_API_KEY"]. The API key requires only the Suppressions permission.

Advanced

For more control over services, set them by hand.

Mailkick.services = [
  Mailkick::Service::SendGridV2.new(api_key: "API_KEY"),
  Mailkick::Service::Mailchimp.new(api_key: "API_KEY", list_id: "LIST_ID")
]

Reference

Access the subscription model directly

Mailkick::Subscription.all

Upgrading

1.0

Mailkick 1.0 stores subscriptions instead of opt-outs. To migrate:

  1. Add a table to store subscriptions
rails generate mailkick:install
rails db:migrate
  1. Change the following methods in your code:
  • mailkick_user to has_subscriptions
  • User.not_opted_out to User.subscribed(list)
  • opt_in to subscribe(list)
  • opt_out to unsubscribe(list)
  1. Add a user and list to mailkick_unsubscribe_url
mailkick_unsubscribe_url(user, list)
  1. Migrate data for each of your lists
opted_out_emails = Mailkick::Legacy.opted_out_emails(list: nil)
opted_out_users = Mailkick::Legacy.opted_out_users(list: nil)

User.find_in_batches do |users|
  users.reject! { |u| opted_out_emails.include?(u.email) }
  users.reject! { |u| opted_out_users.include?(u) }

  now = Time.now
  records =
    users.map do |user|
      {
        subscriber_type: user.class.name,
        subscriber_id: user.id,
        list: "sales",
        created_at: now,
        updated_at: now
      }
    end

  # use create! for Active Record < 6
  Mailkick::Subscription.insert_all!(records)
end
  1. Drop the mailkick_opt_outs table
drop_table :mailkick_opt_outs

Also, if you use Mailkick.fetch_opt_outs, add a method to handle opt outs.

History

View the changelog

Contributing

Everyone is encouraged to help improve this project. Here are a few ways you can help:

To get started with development and testing:

git clone https://github.com/ankane/mailkick.git
cd mailkick
bundle install
bundle exec rake test