feat: IMAP Email Channel (#3298)

This change allows the user to configure both IMAP and SMTP for an email inbox. IMAP enables the user to see emails in Chatwoot. And user can use SMTP to reply to an email conversation.

Users can use the default settings to send and receive emails for email inboxes if both IMAP and SMTP are disabled.

Fixes #2520
This commit is contained in:
Aswin Dev P.S
2021-11-18 22:22:27 -08:00
committed by GitHub
parent 8384d0b38e
commit 24e6a92297
25 changed files with 1040 additions and 57 deletions

View File

@@ -0,0 +1,79 @@
class Imap::ImapMailbox
include MailboxHelper
attr_accessor :channel, :account, :inbox, :conversation, :processed_mail
def process(mail, channel)
@inbound_mail = mail
@channel = channel
load_account
load_inbox
decorate_mail
# prevent loop from chatwoot notification emails
return if notification_email_from_chatwoot?
ActiveRecord::Base.transaction do
find_or_create_contact
find_or_create_conversation
create_message
add_attachments_to_message
end
end
private
def load_account
@account = @channel.account
end
def load_inbox
@inbox = @channel.inbox
end
def decorate_mail
@processed_mail = MailPresenter.new(@inbound_mail, @account)
end
def find_conversation_by_in_reply_to
return if in_reply_to.blank?
message = @inbox.messages.find_by(source_id: in_reply_to)
if message.nil?
@inbox.conversations.where("additional_attributes->>'in_reply_to' = ?", in_reply_to).first
else
@inbox.conversations.find(message.conversation_id)
end
end
def in_reply_to
@inbound_mail.in_reply_to
end
def find_or_create_conversation
@conversation = find_conversation_by_in_reply_to || ::Conversation.create!({ account_id: @account.id,
inbox_id: @inbox.id,
contact_id: @contact.id,
contact_inbox_id: @contact_inbox.id,
additional_attributes: {
source: 'email',
in_reply_to: in_reply_to,
mail_subject: @processed_mail.subject,
initiated_at: {
timestamp: Time.now.utc
}
} })
end
def find_or_create_contact
@contact = @inbox.contacts.find_by(email: @processed_mail.original_sender)
if @contact.present?
@contact_inbox = ContactInbox.find_by(inbox: @inbox, contact: @contact)
else
create_contact
end
end
def identify_contact_name
processed_mail.sender_name || processed_mail.from.first.split('@').first
end
end

View File

@@ -29,6 +29,21 @@ module MailboxHelper
@message.save!
end
def create_contact
@contact_inbox = ::ContactBuilder.new(
source_id: "email:#{processed_mail.message_id}",
inbox: @inbox,
contact_attributes: {
name: identify_contact_name,
email: processed_mail.original_sender,
additional_attributes: {
source_id: "email:#{processed_mail.message_id}"
}
}
).perform
@contact = @contact_inbox.contact
end
def notification_email_from_chatwoot?
# notification emails are send via mailer sender email address. so it should match
@processed_mail.original_sender == Mail::Address.new(ENV.fetch('MAILER_SENDER_EMAIL', 'Chatwoot <accounts@chatwoot.com>')).address

View File

@@ -78,21 +78,6 @@ class SupportMailbox < ApplicationMailbox
end
end
def create_contact
@contact_inbox = ::ContactBuilder.new(
source_id: "email:#{processed_mail.message_id}",
inbox: @inbox,
contact_attributes: {
name: identify_contact_name,
email: @processed_mail.original_sender,
additional_attributes: {
source_id: "email:#{processed_mail.message_id}"
}
}
).perform
@contact = @contact_inbox.contact
end
def identify_contact_name
processed_mail.sender_name || processed_mail.from.first.split('@').first
end