diff options
Diffstat (limited to 'app/models/action_mailbox')
5 files changed, 107 insertions, 0 deletions
diff --git a/app/models/action_mailbox/inbound_email.rb b/app/models/action_mailbox/inbound_email.rb new file mode 100644 index 0000000000..f2589d7429 --- /dev/null +++ b/app/models/action_mailbox/inbound_email.rb @@ -0,0 +1,22 @@ +require "mail" + +class ActionMailbox::InboundEmail < ActiveRecord::Base + self.table_name = "action_mailbox_inbound_emails" + + include Incineratable, MessageId, Routable + + has_one_attached :raw_email + enum status: %i[ pending processing delivered failed bounced ] + + def self.mail_from_source(source) + Mail.new Mail::Utilities.binary_unsafe_to_crlf(source.to_s) + end + + def mail + @mail ||= self.class.mail_from_source(source) + end + + def source + @source ||= raw_email.download + end +end diff --git a/app/models/action_mailbox/inbound_email/incineratable.rb b/app/models/action_mailbox/inbound_email/incineratable.rb new file mode 100644 index 0000000000..6ba73c0c6d --- /dev/null +++ b/app/models/action_mailbox/inbound_email/incineratable.rb @@ -0,0 +1,31 @@ +module ActionMailbox::InboundEmail::Incineratable + extend ActiveSupport::Concern + + # TODO: Extract into framework configuration + INCINERATABLE_AFTER = 30.days + + included do + before_update :remember_to_incinerate_later + after_update_commit :incinerate_later, if: :need_to_incinerate_later? + end + + def incinerate + Incineration.new(self).run + end + + private + # TODO: Use enum change tracking once merged into Active Support + def remember_to_incinerate_later + if status_changed? && (delivered? || failed?) + @incinerate_later = true + end + end + + def need_to_incinerate_later? + @incinerate_later + end + + def incinerate_later + ActionMailbox::InboundEmail::IncinerationJob.schedule(self) + end +end diff --git a/app/models/action_mailbox/inbound_email/incineratable/incineration.rb b/app/models/action_mailbox/inbound_email/incineratable/incineration.rb new file mode 100644 index 0000000000..bd2bf7d91e --- /dev/null +++ b/app/models/action_mailbox/inbound_email/incineratable/incineration.rb @@ -0,0 +1,18 @@ +class ActionMailbox::InboundEmail::Incineratable::Incineration + def initialize(inbound_email) + @inbound_email = inbound_email + end + + def run + @inbound_email.destroy if due? && processed? + end + + private + def due? + @inbound_email.updated_at < ActionMailbox::InboundEmail::Incineratable::INCINERATABLE_AFTER.ago.end_of_day + end + + def processed? + @inbound_email.delivered? || @inbound_email.failed? + end +end diff --git a/app/models/action_mailbox/inbound_email/message_id.rb b/app/models/action_mailbox/inbound_email/message_id.rb new file mode 100644 index 0000000000..590dbfc4d7 --- /dev/null +++ b/app/models/action_mailbox/inbound_email/message_id.rb @@ -0,0 +1,25 @@ +module ActionMailbox::InboundEmail::MessageId + extend ActiveSupport::Concern + + included do + before_save :generate_missing_message_id + end + + module ClassMethods + def create_and_extract_message_id!(raw_email, **options) + create! raw_email: raw_email, message_id: extract_message_id(raw_email), **options + end + + private + def extract_message_id(raw_email) + mail_from_source(raw_email.read).message_id + rescue => e + # FIXME: Add logging with "Couldn't extract Message ID, so will generating a new random ID instead" + end + end + + private + def generate_missing_message_id + self.message_id ||= Mail::MessageIdField.new.message_id + end +end diff --git a/app/models/action_mailbox/inbound_email/routable.rb b/app/models/action_mailbox/inbound_email/routable.rb new file mode 100644 index 0000000000..1928f9e387 --- /dev/null +++ b/app/models/action_mailbox/inbound_email/routable.rb @@ -0,0 +1,11 @@ +module ActionMailbox::InboundEmail::Routable + extend ActiveSupport::Concern + + included do + after_create_commit :route_later, if: ->(inbound_email) { inbound_email.pending? } + end + + def route_later + ActionMailbox::RoutingJob.perform_later self + end +end |