Create an Email Drip Campaign Using Rails Vault
This article is part of Build a SaaS with Rails and was previously published on Rails Designer I recently published the Rails Vault gem. The most obvious (and common) use case is to store settings and preferences for users and workspaces (or teams/accounts). It is how I use it often as well, but recently I built a SaaS for someone that needed a basic email drip campaign (or “automated email campaign”, “lifecycle emails” or “nurture campaign”). I have found Rails Vault can work great for this too. I want to share the lowdown of it. I assume you have installed the gem already. Create the vault That is easy! rails generate rails_vault:add User::EmailDripper \ welcome_email_sent_at:datetime \ engagement_email_sent_at:datetime \ reminder_email_sent_at:datetime This will create a vault at app/models/user/email_dripper.rb: # app/models/user/email_dripper.rb class User::EmailDripper

This article is part of Build a SaaS with Rails and was previously published on Rails Designer
I recently published the Rails Vault gem. The most obvious (and common) use case is to store settings and preferences for users and workspaces (or teams/accounts). It is how I use it often as well, but recently I built a SaaS for someone that needed a basic email drip campaign (or “automated email campaign”, “lifecycle emails” or “nurture campaign”).
I have found Rails Vault can work great for this too. I want to share the lowdown of it. I assume you have installed the gem already.
Create the vault
That is easy!
rails generate rails_vault:add User::EmailDripper \
welcome_email_sent_at:datetime \
engagement_email_sent_at:datetime \
reminder_email_sent_at:datetime
This will create a vault at app/models/user/email_dripper.rb:
# app/models/user/email_dripper.rb
class User::EmailDripper < RailsVault::Base
vault_attribute :welcome_email_sent_at, :datetime
vault_attribute :engagement_email_sent_at, :datetime
vault_attribute :reminder_email_sent_at, :datetime
end
I want to store when an email is sent to the user so they don't get flooded with the same email. Here I want to send three different emails: “welcome_email”, “engagement_email” and “reminder_email”. You can name them however you want.
Email Drip Logic
Next is a class that holds all the logic to determine which email to send to which user.
# app/models/email_dripper.rb
class EmailDripper
STEPS = {
2.hours => :welcome_email,
24.hours => :engagement_email,
72.hours => :reminder_email
}
RECENT_SIGNUP_THRESHOLD = 72.hours
class << self
def call
User.where(created_at: RECENT_SIGNUP_THRESHOLD.ago..).find_each { process(it) }
end
private
def process(user)
return if user.email_dripper.blank?
STEPS.each { process_step_for(user, _1, _2) }
end
def process_step_for(user, delay, email)
scheduled_time = user.created_at + delay
return if scheduled_time.future?
return if already_sent? email, to: user
DripMailer.public_send(identifier, user).deliver_now
end
def already_sent?(email, to:) = to.email_dripper&.public_send(email).present?
end
end
The STEPS
hash defines a sequence of three emails scheduled at 2, 24, and 72 hours after signup. Feel free to tweak to make sense for your product. The RECENT_SIGNUP_THRESHOLD
constant sets a 72-hour window for considering users as recent signups, just to limit the users needed to query. The call
method processes all users who signed up within the recent threshold.
Then the process
method checks if a user has email dripping enabled and iterates through the campaign's “steps”. The process_step_for
method handles individual email steps by checking if it's time to send and hasn't been sent before. The already_sent?
method verifies if a specific campaign email has already been sent to the user (see how I like my code to be readable?). The actual email sending is handled through DripMailer
using Ruby's public_send
.
Then create the the DripMailer class:
# app/mailers/drip_mailer.rb
class DripMailer < ApplicationMailer
def welcome_email(user)
mail(
to: user.email,
subject: "Welcome to Rails Designer!"
)
end
def engagement_email(user)
#…
end
def reminder_email(user)
#…
end
end
Don't forget to create the corresponding views as well:
app/views/drip_mailer/
├── welcome_email.html.erb
├── engagement_email.html.erb
└── reminder_email.html.erb
Finally make sure to run EmailDripper.call
at a regular interval using a cron. How that is done depends on your app's setup.
And there you have it: an easy-to-use and expandable way to send an email drip campaign to your Rails app's users.