# frozen_string_literals: true require "aws-sdk-s3" require "mail" require "shoryuken" module Jobshop # Jobshop::Postmaster # # Reponsible for processing incoming email and dispatching it to its handler. class Postmaster include Shoryuken::Worker shoryuken_options queue: Jobshop.configuration.aws.incoming_email_queue def perform(sqs_msg, *) @event = S3EventMessage.new(sqs_msg.body) || return tempfile = Tempfile.new s3.get_object({ bucket: @event.bucket, key: @event.key }, target: tempfile) message = Mail.new(File.read(tempfile)) recipient = Mail::Address.new(message.to.first) mailbox = recipient.local.split("+").first handler_address = "#{mailbox}@#{recipient.domain}" mailman = Mailman.find_by(address: handler_address) # TODO: If no mailman registered, look for domain. If no domain found # TODO: treat as spam. if mailman klass = mailman.handler_type.constantize handler = klass.new(message, organization: mailman.organization) success = handler.process if success copy_to(handler.processed_copy_prefix) if handler.copy_after_processing? delete_incoming if handler.delete_after_processing? sqs_msg.delete end else return end ensure @event = nil tempfile.close tempfile.unlink end def s3 @s3 ||= Aws::S3::Client.new end def copy_to(prefix) key = prefix + "/" + @event.key.split("/").last s3.copy_object({ copy_source: @event.bucket + "/" + @event.key, bucket: Jobshop.configuration.aws.s3_bucket, key: key }) || raise("Could not copy incoming rfq to processed folder") end def delete_incoming s3.delete_object({ bucket: @event.bucket, key: @event.key }) || raise("Could not delete incoming email") end class S3EventMessage def initialize(message) @message = JSON.parse(message) return false unless records end def records @records ||= @message["Records"] || [] end def bucket records.first.dig "s3", "bucket", "name" end def key records.first.dig "s3", "object", "key" end end end end