-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: email channel backend (#140) (#1255)
* feat: added support mailbox to handle email channel (#140) Added a new mailbox called 'SupportMailbox' to handle all the incoming emails other than reply emails. An email channel will have a support email and forward email associated with it. So we filter for the right email inbox based on the support email of that inbox and route this to this mailbox. This mailbox finds the account, inbox, contact (create a new one if it does not exist) and creates a conversation and adds the email content as the first message in the conversation. Other minor things handled in this commit: * renamed the procs for routing emails in application mailbox * renamed ConversationMailbox to ReplyMailbox * Added a fallback content in MailPresenter * Added a record saving (bang) versions of enabling and disabling features in Featurable module * added new factory for the email channel refs: #140
- Loading branch information
1 parent
313b2da
commit f9b0427
Showing
12 changed files
with
892 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,7 @@ | |
*.log | ||
# Ignore application configuration | ||
node_modules | ||
|
||
master.key | ||
*.rdb | ||
|
||
# Ignore env files | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ class ApplicationMailbox < ActionMailbox::Base | |
# Eg: email should be something like : [email protected] | ||
REPLY_EMAIL_USERNAME_PATTERN = /^reply\+([0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12})$/i.freeze | ||
|
||
def self.reply_match_proc | ||
def self.reply_mail? | ||
proc do |inbound_mail_obj| | ||
is_a_reply_email = false | ||
inbound_mail_obj.mail.to.each do |email| | ||
|
@@ -18,11 +18,26 @@ def self.reply_match_proc | |
end | ||
end | ||
|
||
def self.default_mail_proc | ||
def self.support_mail? | ||
proc do |inbound_mail_obj| | ||
is_a_support_email = false | ||
inbound_mail_obj.mail.to.each do |email| | ||
channel = Channel::Email.find_by(email: email) | ||
if channel.present? | ||
is_a_support_email = true | ||
break | ||
end | ||
end | ||
is_a_support_email | ||
end | ||
end | ||
|
||
def self.catch_all_mail? | ||
proc { |_mail| true } | ||
end | ||
|
||
# routing should be defined below the referenced procs | ||
routing(reply_match_proc => :conversation) | ||
routing(default_mail_proc => :default) | ||
routing(reply_mail? => :reply) | ||
routing(support_mail? => :support) | ||
routing(catch_all_mail? => :default) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
module MailboxHelper | ||
private | ||
|
||
def create_message | ||
@message = @conversation.messages.create( | ||
account_id: @conversation.account_id, | ||
sender: @conversation.contact, | ||
content: processed_mail.text_content[:reply], | ||
inbox_id: @conversation.inbox_id, | ||
message_type: 'incoming', | ||
content_type: 'incoming_email', | ||
source_id: processed_mail.message_id, | ||
content_attributes: { | ||
email: processed_mail.serialized_data | ||
} | ||
) | ||
end | ||
|
||
def add_attachments_to_message | ||
processed_mail.attachments.each do |mail_attachment| | ||
attachment = @message.attachments.new( | ||
account_id: @conversation.account_id, | ||
file_type: 'file' | ||
) | ||
attachment.file.attach(mail_attachment[:blob]) | ||
end | ||
@message.save! | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
class SupportMailbox < ApplicationMailbox | ||
include MailboxHelper | ||
|
||
attr_accessor :channel, :account, :inbox, :conversation, :processed_mail | ||
|
||
before_processing :find_channel, | ||
:load_account, | ||
:load_inbox, | ||
:decorate_mail | ||
|
||
def process | ||
find_or_create_contact | ||
create_conversation | ||
create_message | ||
add_attachments_to_message | ||
end | ||
|
||
private | ||
|
||
def find_channel | ||
mail.to.each do |email| | ||
@channel = Channel::Email.find_by(email: email) | ||
break if @channel.present? | ||
end | ||
raise 'Email channel/inbox not found' if @channel.nil? | ||
|
||
@channel | ||
end | ||
|
||
def load_account | ||
@account = @channel.account | ||
end | ||
|
||
def load_inbox | ||
@inbox = @channel.inbox | ||
end | ||
|
||
def decorate_mail | ||
@processed_mail = MailPresenter.new(mail, @account) | ||
end | ||
|
||
def create_conversation | ||
@conversation = ::Conversation.create!({ | ||
account_id: @account.id, | ||
inbox_id: @inbox.id, | ||
contact_id: @contact.id, | ||
contact_inbox_id: @contact_inbox.id, | ||
additional_attributes: { | ||
source: 'email', | ||
initiated_at: { | ||
timestamp: Time.now.utc | ||
} | ||
} | ||
}) | ||
end | ||
|
||
def find_or_create_contact | ||
@contact = @inbox.contacts.find_by(email: processed_mail.from.first) | ||
if @contact.present? | ||
@contact_inbox = ContactInbox.find_by(inbox: @inbox, contact: @contact) | ||
else | ||
create_contact | ||
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.from.first, | ||
additional_attributes: { | ||
source_id: "email:#{processed_mail.message_id}" | ||
} | ||
} | ||
).perform | ||
@contact = @contact_inbox.contact | ||
end | ||
|
||
def identify_contact_name | ||
processed_mail.from.first.split('@').first | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# frozen_string_literal: true | ||
|
||
FactoryBot.define do | ||
factory :channel_email, class: 'Channel::Email' do | ||
sequence(:email) { |n| "care-#{n}@example.com" } | ||
sequence(:forward_to_address) { |n| "forward-#{n}@chatwoot.com" } | ||
account | ||
after(:create) do |channel_email| | ||
create(:inbox, channel: channel_email, account: channel_email.account) | ||
end | ||
end | ||
end |
Oops, something went wrong.