An opinionated rails drip email engine that depends on ActiveRecord and ActionMailer
DRY up your mailer code with a rules-based drip campaign system that works natively with rails and ActionMailer.
I needed a DRIP email service, and as both developer and marketer, I wanted to build something that works easily with rails. Most DRIP SAAS products are too expensive for websites where visitors don't pay. I love sites like intercom, but they don't make sense unless are generating revenue.
Clean up your email messaging code by creating a rails model for each message. So, instead of trying to navigate through your user to an order, chat, message, or whatever, you just put the rules on the chat, order and message.
bundle install
gem 'dripper_mail'
rake dripper:install:migrations
rake db:migrate
Dripper.config model: :users do
# send a welcome message when a user is created
dripper mailer: :welcome_mailer, action: :welcome
end
class Newsletter < ActiveRecord::Base
include Dripper::Drippable
belongs_to :user
end
This example expects you to have a mailer method that looks like this:
class UserMailer < ApplicationMailer
def newsletter(newsletter)
mail to: "[email protected]"
end
end
Simply create a new model and insert it into your database. your Mail code will get called automatically.
rails c
Newsletter.create(user: User.first, subject: "Hello!")
dripper model: :orders do
# send a successful order message
dripper mailer: :order_mailer, action: :new_order, scope: -> { paid }
end
Use a proc for wait_until so that it gets evaluated at the correct time.
dripper model: :users do
dripper mailer: :welcome_mailer, action: :welcome, scope: -> { new_user }, wait_until: -> { Date.tomorrow.noon }
dripper mailer: :welcome_mailer, action: :welcome, scope: -> { new_user }, wait: -> { 1.hours }
end
Drip messages are designed to get people to take specific actions based on their lifecycle
In this case, we want to sent 3 messages, on day 1,3 and 7. We only want to send the last message if they haven't subscribed.
Note that we can nest options (mailer, scope, model, etc) which makes the code cleaner
class User
scope :day_count, ->(day_count) {where("created_at < ?", DateTime.now - day_count.days) }
scope :no_customer, -> {where.not(:id => Subscription.select(:user_id).uniq) }
scope :customer, -> {joins(:subscriptions).where("subscriptions.is_active = true") }
end
dripper model: :users, scope: -> { confirmed } do
dripper mailer: :onboarding do
dripper action: :day1, scope: -> { day_count(1) }
dripper action: :day3, scope: -> { day_count(3) }
dripper action: :day7_no_customer, scope: -> { day_count(7).merge(-> { no_customer } ) }
dripper action: :day7_customer, scope: -> { day_count(7).merge(-> { customer } ) }
end
end
This could potentially replace devise's awful mess :)
dripper model: :users do
dripper mailer: :user_mailer, action: :confirmation, scope: -> { unconfirmed }
end
This will send a password changed email if the password has been changed in the last 30 minutes
dripper model: :users do
dripper mailer: :user_mailer, action: :change_password, scope: -> { password_changed(30.minutes.ago) }
end
# define inactive scope
class User
scope :inactive, -> { where("last_session_at < ?", DateTime.today - 1.months) }
end
# dripper code uses scope
dripper model: :users do
dripper mailer: :user_mailer, action: :inactive, scope: :inactive, -> { inactive }
end
Notice in this case, we will only send 1 inactive message, ever. Also this one would require a rake task , as the user would not be triggering it (since they are inactive) Alternatively you could have a rake task that sets inactive_at.
If you want to send more than one, you should create a new model that corresponds to the mailer. Run a rake task that populates this model.
This may sounds like a pain, but things will be cleaner and you will be able to control what gets sent when. You'll also get the benefit of seeing your inactive users in a nice queryable format.
Here's how that would look:
class InactiveUser
# user_id, :integer
# inactive_at :datetime
belongs_to :user
end
dripper :inactive_users do
dripper :inactive_mailer, -> {:inactive}
end
This will send a new email on every chat
dripper :chat_message do
dripper :chat_mailer, :new_chat
end
Similarly, in this case, if we want to send a weekly digest, we should have a weekly digest AR model that gets populated by a rake task.
class WeeklyDigest
belongs_to :user
# week_start_on, week_end_on
# other stuff
def self.create_weekly_digest(start_on)
User.all.each do |u|
u.weekly_digests.create week_start_on: start_on, week_end_on: start_on + 1.weeks
end
end
end
dripper model: :weekly_digest do
dripper mailer: :digest_mailer, action: :weekly_digest
end
NOTE: this doesn't work yet...
# runs all open drippers
rake dripper:run
This project rocks and uses MIT-LICENSE.