Caffeinate - Josh Brody Caffeinate | Josh Brody
All projects
Ruby Gem

Caffeinate

Drip campaign engine for Rails.

Caffeinate handles scheduled sequences in Rails, typically meant to stimulate a user. You define a dripper class, specify your drips (actions) with delays, subscribe (usually) users, and let it run. Originally built for emails via ActionMailer, it now works with any Ruby object.

Why it exists

Drip campaigns in Rails usually end up as a mess of delayed jobs, boolean flags on user models, and mailer methods that check too many conditions. Unsubscribe logic gets scattered. Timing logic gets duplicated. The whole thing becomes hard to reason about.

Caffeinate moves all of that into one place. A dripper defines the sequence. A subscription tracks where a user is in that sequence. Mailings represent individual sends. The mental model is simple; the implementation stays that way too.

How it works

Three concepts:

  • Dripper: a class that defines a campaign’s drips and their timing;
  • Subscription: tracks a subscriber’s enrollment and progress;
  • Mailing: represents a single scheduled send.

Drippers declare drips with a delay. When you subscribe someone, Caffeinate creates mailings for each drip. A periodic job processes mailings that are due. That’s it.

Conditional logic

Use before_drip callbacks to skip or cancel drips based on current state:

before_drip do |drip, mailing|
  if mailing.subscription.subscriber.completed_onboarding?
    mailing.subscription.unsubscribe!("Completed onboarding")
    throw(:abort)
  end
end

The callback runs right before sending. If something changed since the mailing was scheduled, you can bail out cleanly.

Beyond email

Drips can use any object, not just mailers:

drip :sms_reminder, action_class: 'SmsNotifier', action_method: :remind, delay: 1.day

The class just needs to respond to the method with a mailing argument. Useful for multi-channel sequences or non-email workflows entirely.

Unsubscribe handling

Subscriptions track unsubscribe state and optionally a reason. Build analytics on why people leave. No more unsubscribed_at columns scattered across your models.

Production tested

Originally used at HeheStreams with, according to the government, 33,000 users. The low commit activity reflects stability, and my (present) inability to access my GitHub account.

Stack

Ruby Rails ActionMailer

Stay in the loop

Occasional essays on design, tools, and the craft of building things. No spam, unsubscribe anytime.

Ambient weather

The background of this site reflects the current weather and time of day in Saint Paul. The orbs shift in color and behavior based on what's happening outside my window.

Learn more about how this works