chore: Migrate mailers from the worker to jobs (#12331)
Previously, email replies were handled inside workers. There was no execution logs. This meant if emails silently failed (as reported by a customer), we had no way to trace where the issue happened, the only assumption was “no error = mail sent.” By moving email handling into jobs, we now have proper execution logs for each attempt. This makes it easier to debug delivery issues and would have better visibility when investigating customer reports. Fixes https://linear.app/chatwoot/issue/CW-5538/emails-are-not-sentdelivered-to-the-contact --------- Co-authored-by: Sojan Jose <sojan@pepalo.com> Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
18
app/services/email/send_on_email_service.rb
Normal file
18
app/services/email/send_on_email_service.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
class Email::SendOnEmailService < Base::SendOnChannelService
|
||||
private
|
||||
|
||||
def channel_class
|
||||
Channel::Email
|
||||
end
|
||||
|
||||
def perform_reply
|
||||
return unless message.email_notifiable_message?
|
||||
|
||||
reply_mail = ConversationReplyMailer.with(account: message.account).email_reply(message).deliver_now
|
||||
Rails.logger.info("Email message #{message.id} sent with source_id: #{reply_mail.message_id}")
|
||||
message.update(source_id: reply_mail.message_id)
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e, account: message.account).capture_exception
|
||||
Messages::StatusUpdateService.new(message, 'failed', e.message).perform
|
||||
end
|
||||
end
|
||||
38
app/services/messages/send_email_notification_service.rb
Normal file
38
app/services/messages/send_email_notification_service.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
class Messages::SendEmailNotificationService
|
||||
pattr_initialize [:message!]
|
||||
|
||||
def perform
|
||||
return unless should_send_email_notification?
|
||||
|
||||
conversation = message.conversation
|
||||
conversation_mail_key = format(::Redis::Alfred::CONVERSATION_MAILER_KEY, conversation_id: conversation.id)
|
||||
|
||||
# Atomically set redis key to prevent duplicate email workers. Keep the key alive longer than
|
||||
# the worker delay (1 hour) so slow queues don't enqueue duplicate jobs, but let it expire if
|
||||
# the worker never manages to clean up.
|
||||
return unless Redis::Alfred.set(conversation_mail_key, message.id, nx: true, ex: 1.hour.to_i)
|
||||
|
||||
ConversationReplyEmailWorker.perform_in(2.minutes, conversation.id, message.id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def should_send_email_notification?
|
||||
return false unless message.email_notifiable_message?
|
||||
return false if message.conversation.contact.email.blank?
|
||||
|
||||
email_reply_enabled?
|
||||
end
|
||||
|
||||
def email_reply_enabled?
|
||||
inbox = message.inbox
|
||||
case inbox.channel.class.to_s
|
||||
when 'Channel::WebWidget'
|
||||
inbox.channel.continuity_via_email
|
||||
when 'Channel::Api'
|
||||
inbox.account.feature_enabled?('email_continuity_on_api_channel')
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user