Ruby on Rails archive

Email Digests

Instead of emailing users on every action, combine all notifications over a certain period of time into a single email.

Built with the griddler gem, this series reflects inbound-email handling of its time rather than Rails' Action Mailbox.

This article builds on top of the Mailing Lists functionality.

Email digests contain all messages since the previous digest. We'll generate a daily digest using the whenever gem which manages scheduled tasks defined inside config/schedule.rb

# app/mailers/groups_mailer.rb
class GroupsMailer < ApplicationMailer
  def digest(membership, timeframe)
    @membership = membership
    @group = membership.group
    @messages = @group.messages.where(created_at: timeframe).order(:discussion_id, :created_at)

    mail(
      to: @membership.user.email,
      from: %("#{@group.name}" <#{@group.email}>),
      subject: "[#{@group.name}] Message Digest",
    )
  end
end
<!-- app/views/groups_mailer/digest.html.erb -->
<%= @messages.each do |message| %>
  <p>Subject: <%= message.discussion.subject %></p>
  <p>From: <%= message.from.name %></p>
  <p>Timestamp: <%= message.created_at.to_fs(:timestamp) %></p>
  <%= simple_format message.content %>
  <hr>
<% end %>

<p><%= link_to 'Unsubscribe', unsubscribe_url(id: @membership.token) %></p>
# lib/tasks/groups.rake
namespace :groups do
  namespace :digest do
    task send: :environment do
      Groups.find_each do |group|
        now = Time.zone.now
        last_sent = group.digest_last_sent_at || (now - 1.week)
        timeframe = (last_sent..now)

        next if group.messages.where(created_at: timeframe).empty?

        group.memberships.where(receives_digest: true).find_each do |membership|
          GroupsMailer.digest(membership, timeframe).deliver_later
        end

        group.digest_last_sent_at = now
        group.save(validate: false)
      end
    end
  end
end
# config/schedule.rb
every 1.day, at: "4:30 am" do
  rake "groups:digest:send"
end
Dan Cunning

Dan Cunning

Ruby on Rails contractor from Atlanta GA, focusing on simplicity and usability through solid design.