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