discourse/app/jobs/regular/group_smtp_email.rb
Martin Brennan 87684f7c5e
FEATURE: Use group SMTP job and mailer instead of UserNotifications change (#13489)
This PR backtracks a fair bit on this one https://github.com/discourse/discourse/pull/13220/files.

Instead of sending the group SMTP email for each user via `UserNotifications`, we are changing to send only one email with the existing `Jobs::GroupSmtpEmail` job and `GroupSmtpMailer`. We are changing this job and mailer along with `PostAlerter` to make the first topic allowed user the `to_address` for the email and any other `topic_allowed_users` to be the CC address on the email. This is to cut down on emails sent via SMTP, which is subject to daily limits from providers such as Gmail. We log these details in the `EmailLog` table now.

In addition to this, we have changed `PostAlerter` to no longer rely on incoming email email addresses for sending the `GroupSmtpEmail` job. This was unreliable as a user's email could have changed in the meantime. Also it was a little overcomplicated to use the incoming email records -- it is far simpler to reason about to just use topic allowed users.

This also adds a fix to include cc_addresses in the EmailLog.addressed_to_user scope.
2021-06-28 08:55:13 +10:00

57 lines
2.2 KiB
Ruby

# frozen_string_literal: true
require_dependency 'email/sender'
module Jobs
class GroupSmtpEmail < ::Jobs::Base
sidekiq_options queue: 'critical'
def execute(args)
group = Group.find_by(id: args[:group_id])
post = Post.find_by(id: args[:post_id])
email = args[:email]
cc_addresses = args[:cc_emails]
# There is a rare race condition causing the Imap::Sync class to create
# an incoming email and associated post/topic, which then kicks off
# the PostAlerter to notify others in the PM about a reply in the topic,
# but for the OP which is not necessary (because the person emailing the
# IMAP inbox already knows about the OP)
#
# Basically, we should never be sending this notification for the first
# post in a topic.
if post.is_first_post?
ImapSyncLog.warn("Aborting SMTP email for post #{post.id} in topic #{post.topic_id} to #{email}, the post is the OP and should not send an email.", group)
return
end
ImapSyncLog.debug("Sending SMTP email for post #{post.id} in topic #{post.topic_id} to #{email}.", group)
recipient_user = ::UserEmail.find_by(email: email, primary: true)&.user
message = GroupSmtpMailer.send_mail(group, email, post, cc_addresses)
# The EmailLog record created by the sender will have the raw email
# stored, the group smtp ID, and any cc addresses recorded for later
# cross referencing.
Email::Sender.new(message, :group_smtp, recipient_user).send
# Create an incoming email record to avoid importing again from IMAP
# server. While this may not be technically required if IMAP is not
# currently enabled for the group, it will help a lot with the initial
# sync if it is turned on at a later date.
IncomingEmail.create!(
user_id: post.user_id,
topic_id: post.topic_id,
post_id: post.id,
raw: message.to_s,
subject: message.subject,
message_id: message.message_id,
to_addresses: message.to,
cc_addresses: message.cc,
from_address: message.from,
created_via: IncomingEmail.created_via_types[:group_smtp]
)
end
end
end