Go to file
David Heinemeier Hansson 1df26841b3 Note about incineration
2018-12-12 16:06:56 -08:00
app Base note 2018-12-12 16:06:48 -08:00
bin First end-to-end rickety test 2018-09-17 22:15:27 -07:00
config Revert "Nest" 2018-11-22 16:40:30 -05:00
db/migrate Delete .DS_Store files 2018-10-03 15:43:20 -04:00
lib Address objects are value objects 2018-12-06 13:54:09 -08:00
test Address objects are value objects 2018-12-06 13:54:09 -08:00
.gitignore Tmp files 2018-09-19 15:15:10 -07:00
actionmailbox.gemspec George ended up doing a lot of the actual code 2018-12-12 15:42:03 -08:00
Gemfile Accept inbound emails from a variety of ingresses 2018-10-11 12:51:13 -04:00
Gemfile.lock Extract ActionMailbox::PostfixRelayer 2018-11-25 15:36:08 -05:00
LICENSE Skeleton 2018-09-17 16:30:33 -07:00
Rakefile Skeleton 2018-09-17 16:30:33 -07:00
README.md Note about incineration 2018-12-12 16:06:56 -08:00

Action Mailbox

Action Mailbox routes incoming emails to controller-like mailboxes for further and encapsulated processing in Rails.

It ships with ingress handling for AWS SNS, Mailgun, Madrill, and Sendgrid. You can also handle inbound mails directly via the Postfix ingress task/controller combination.

The inbound emails are turned into InboundEmail records using Active Record and feature lifecycle tracking, storage of the original email on cloud storage via Active Storage, and responsible data handling with on-by-default incineration.

These inbound emails are routed asynchronously using Active Job to one or several dedicated mailboxes, which are capable of interacting directly with the rest of your domain model.

How does this compare to Action Mailer's inbound processing?

Rails has long had an anemic way of receiving emails using Action Mailer, but it was poorly flushed out, lacked cohesion with the task of sending emails, and offered no help on integrating with popular inbound email processing platforms. Action Mailbox supersedes the receiving part of Action Mailer, which will be deprecated in due course.

Installing

Assumes a Rails 5.2+ application:

  1. Install the gem:

    # Gemfile
    gem "actionmailbox", github: "rails/actionmailbox", require: "action_mailbox"
    
  2. Install migrations needed for InboundEmail (and ensure Active Storage is setup)

    ./bin/rails action_mailbox:install
    ./bin/rails db:migrate
    

Configure ingress path and password

TODO

Examples

Configure basic routing:

# app/models/message.rb
class ApplicationMailbox < ActionMailbox::Base
  routing /^save@/i     => :forwards
  routing /@replies\./i => :replies
end

Then setup a mailbox:

# app/mailboxes/forwards_mailbox.rb
class ForwardsMailbox < ApplicationMailbox
  # Callbacks specify prerequisites to processing
  before_processing :require_forward

  def process
    if forwarder.buckets.one?
      record_forward
    else
      stage_forward_and_request_more_details
    end
  end

  private
    def require_forward
      unless message.forward?
        # Use Action Mailers to bounce incoming emails back to sender  this halts processing
        bounce_with Forwards::BounceMailer.missing_forward(
          inbound_email, forwarder: forwarder
        )
      end
    end

    def forwarder
      @forwarder ||= Person.where(email_address: mail.from)
    end

    def record_forward
      forwarder.buckets.first.record \
        Forward.new forwarder: forwarder, subject: message.subject, content: mail.content
    end

    def stage_forward_and_request_more_details
      Forwards::RoutingMailer.choose_project(mail).deliver_now
    end
end

Incineration of InboundEmails

By default, an InboundEmail that has been marked as successfully processed will be incinerated after 30 days. This ensures you're not holding on to people's data willy-nilly after they may have canceled their accounts or deleted their content. The intention is that after you've processed an email, you should have extracted all the data you needed and turned it into domain models and content on your side of the application. The InboundEmail simply stays in the system for the extra time to provide debugging and forensics options.

The actual incineration is done via the IncinerationJob that's scheduled to run after config.action_mailbox.incinerate_after time. This value is by default set to 30.days, but you can change it in your production.rb configuration. (Note that this far-future incineration scheduling relies on your job queue being able to hold jobs for that long.)

Create incoming email through a conductor module in development

It's helpful to be able to test incoming emails in development without actually sending and receiving real emails. To accomplish this, there's a conductor controller mounted at /rails/conductor/action_mailbox/inbound_emails, which gives you an index of all the InboundEmails in the system, their state of processing, and a form to create a new InboundEmail as well.

Development road map

Action Mailbox is destined for inclusion in Rails 6, which is due to be released some time in 2019. We will refine the framework in this separate rails/actionmailbox repository until we're ready to promote it via a pull request to rails/rails.

License

Action Mailbox is released under the MIT License.