CINXE.COM
Action Mailbox Basics — Ruby on Rails Guides
<!doctype html> <html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Action Mailbox Basics — Ruby on Rails Guides</title> <link rel="stylesheet" type="text/css" href="stylesheets/style-6fc5bf25e695f363fd1dd3d9dbb2f997.css" data-turbo-track="reload"> <link rel="stylesheet" type="text/css" href="stylesheets/print-a87ee66d50ce96bb83ac082f1249fe3e.css" media="print"> <link rel="stylesheet" type="text/css" href="stylesheets/highlight-2794201d063bd2e4dbd0f0874c2a3f6f.css" data-turbo-track="reload"> <link rel="icon" href="images/favicon.ico" sizes="any"> <link rel="apple-touch-icon" href="images/icon.png"> <link rel="canonical" href="https://guides.rubyonrails.org/action_mailbox_basics.html"> <script src="javascripts/@hotwired--turbo-764f59c7edbeb902a9068c0340dd274e.js" data-turbo-track="reload"></script> <script src="javascripts/clipboard-8b7aed6f069f0cf58eeae353cd2f898b.js" data-turbo-track="reload"></script> <script src="javascripts/guides-751b87e159daf790ddf7e8e88ad8465a.js" data-turbo-track="reload"></script> <meta property="og:title" content="Action Mailbox Basics — Ruby on Rails Guides" /> <meta name="description" content="Action Mailbox BasicsThis guide provides you with all you need to get started in receiving emails to your application.After reading this guide, you will know: How to receive email within a Rails application. How to configure Action Mailbox. How to generate and route emails to a mailbox. How to test incoming emails." /> <meta property="og:description" content="Action Mailbox BasicsThis guide provides you with all you need to get started in receiving emails to your application.After reading this guide, you will know: How to receive email within a Rails application. How to configure Action Mailbox. How to generate and route emails to a mailbox. How to test incoming emails." /> <meta property="og:locale" content="en_US" /> <meta property="og:site_name" content="Ruby on Rails Guides" /> <meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" /> <meta property="og:type" content="website" /> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Heebo:wght@100..900&family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet"> <meta name="theme-color" content="#C81418"> </head> <body dir="ltr" class="guide no-js"> <script> document.body.classList.remove('no-js') </script> <a id="main-skip-link" href="#main" class="skip-link" data-turbo="false"> Skip to main content </a> <div id="mobile-navigation-bar"> <div class="wrapper"> <strong class="more-info-label">More at <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong> <button type="button" class="js-only red-button more-info-button" id="more-info" aria-controls="more-info-links" aria-expanded="false"> More Ruby on Rails </button> <ul id="more-info-links" class="more-info-links hidden"> <li class="more-info"><a href="https://rubyonrails.org/blog">Blog</a></li> <li class="more-info"><a href="https://guides.rubyonrails.org/">Guides</a></li> <li class="more-info"><a href="https://api.rubyonrails.org/">API</a></li> <li class="more-info"><a href="https://discuss.rubyonrails.org/">Forum</a></li> <li class="more-info"><a href="https://github.com/rails/rails">Contribute on GitHub</a></li> </ul> </div> </div> <header id="page-header"> <div class="wrapper clearfix"> <nav id="feature-nav"> <div class="header-logo"> <a href="index.html" title="Guides home for v8.0.1 Guides">Guides</a> <span id="version-switcher" class="js-only"> <label for="version-switcher-select">Version: <span class="visibly-hidden">pick from the list to go to that Rails version's guides</span></label> <select id="version-switcher-select" class="guides-version"> <option value="https://edgeguides.rubyonrails.org/">Edge</option> <option value="https://guides.rubyonrails.org/v8.0/action_mailbox_basics.html" selected>8.0</option> <option value="https://guides.rubyonrails.org/v7.2/action_mailbox_basics.html">7.2</option> <option value="https://guides.rubyonrails.org/v7.1/action_mailbox_basics.html">7.1</option> <option value="https://guides.rubyonrails.org/v7.0/action_mailbox_basics.html">7.0</option> <option value="https://guides.rubyonrails.org/v6.1/action_mailbox_basics.html">6.1</option> <option value="https://guides.rubyonrails.org/v6.0/action_mailbox_basics.html">6.0</option> <option value="https://guides.rubyonrails.org/v5.2/action_mailbox_basics.html">5.2</option> <option value="https://guides.rubyonrails.org/v5.1/action_mailbox_basics.html">5.1</option> <option value="https://guides.rubyonrails.org/v5.0/action_mailbox_basics.html">5.0</option> <option value="https://guides.rubyonrails.org/v4.2/action_mailbox_basics.html">4.2</option> <option value="https://guides.rubyonrails.org/v4.1/action_mailbox_basics.html">4.1</option> <option value="https://guides.rubyonrails.org/v4.0/action_mailbox_basics.html">4.0</option> <option value="https://guides.rubyonrails.org/v3.2/action_mailbox_basics.html">3.2</option> <option value="https://guides.rubyonrails.org/v3.1/action_mailbox_basics.html">3.1</option> <option value="https://guides.rubyonrails.org/v3.0/action_mailbox_basics.html">3.0</option> <option value="https://guides.rubyonrails.org/v2.3/action_mailbox_basics.html">2.3</option> </select> </span> </div> <ul class="nav"> <li><a class="nav-item" id="home_nav" href="https://rubyonrails.org/">Home</a></li> <li class="guides-index guides-index-large"> <a href="index.html" id="guides-menu-button" data-aria-controls="guides" data-aria-expanded="false" class="guides-index-item nav-item">Guides Index</a> <div id="guides" class="clearfix" style="display: none;"> <hr /> <dl class="guides-section-container"> <div class="guides-section"> <dt>Start Here</dt> <dd><a href="getting_started.html">Getting Started with Rails</a></dd> <dd><a href="install_ruby_on_rails.html">Install Ruby on Rails</a></dd> </div> <div class="guides-section"> <dt>Models</dt> <dd><a href="active_record_basics.html">Active Record Basics</a></dd> <dd><a href="active_record_migrations.html">Active Record Migrations</a></dd> <dd><a href="active_record_validations.html">Active Record Validations</a></dd> <dd><a href="active_record_callbacks.html">Active Record Callbacks</a></dd> <dd><a href="association_basics.html">Active Record Associations</a></dd> <dd><a href="active_record_querying.html">Active Record Query Interface</a></dd> <dd><a href="active_model_basics.html">Active Model Basics</a></dd> </div> <div class="guides-section"> <dt>Views</dt> <dd><a href="action_view_overview.html">Action View Overview</a></dd> <dd><a href="layouts_and_rendering.html">Layouts and Rendering in Rails</a></dd> <dd><a href="action_view_helpers.html">Action View Helpers</a></dd> <dd><a href="form_helpers.html">Action View Form Helpers</a></dd> </div> <div class="guides-section"> <dt>Controllers</dt> <dd><a href="action_controller_overview.html">Action Controller Overview</a></dd> <dd><a href="action_controller_advanced_topics.html">Action Controller Advanced Topics</a></dd> <dd><a href="routing.html">Rails Routing from the Outside In</a></dd> </div> <div class="guides-section"> <dt>Other Components</dt> <dd><a href="active_support_core_extensions.html">Active Support Core Extensions</a></dd> <dd><a href="action_mailer_basics.html">Action Mailer Basics</a></dd> <dd><a href="action_mailbox_basics.html">Action Mailbox Basics</a></dd> <dd><a href="action_text_overview.html">Action Text Overview</a></dd> <dd><a href="active_job_basics.html">Active Job Basics</a></dd> <dd><a href="active_storage_overview.html">Active Storage Overview</a></dd> <dd><a href="action_cable_overview.html">Action Cable Overview</a></dd> </div> <div class="guides-section"> <dt>Digging Deeper</dt> <dd><a href="i18n.html">Rails Internationalization (I18n) API</a></dd> <dd><a href="testing.html">Testing Rails Applications</a></dd> <dd><a href="debugging_rails_applications.html">Debugging Rails Applications</a></dd> <dd><a href="configuring.html">Configuring Rails Applications</a></dd> <dd><a href="command_line.html">The Rails Command Line</a></dd> <dd><a href="asset_pipeline.html">The Asset Pipeline</a></dd> <dd><a href="working_with_javascript_in_rails.html">Working with JavaScript in Rails</a></dd> <dd><a href="autoloading_and_reloading_constants.html">Autoloading and Reloading</a></dd> <dd><a href="api_app.html">Using Rails for API-only Applications</a></dd> </div> <div class="guides-section"> <dt>Going to Production</dt> <dd><a href="tuning_performance_for_deployment.html">Tuning Performance for Deployment</a></dd> <dd><a href="caching_with_rails.html">Caching with Rails: An Overview</a></dd> <dd><a href="security.html">Securing Rails Applications</a></dd> <dd><a href="error_reporting.html">Error Reporting in Rails Applications</a></dd> </div> <div class="guides-section"> <dt>Advanced Active Record</dt> <dd><a href="active_record_multiple_databases.html">Multiple Databases</a></dd> <dd><a href="active_record_composite_primary_keys.html">Composite Primary Keys</a></dd> </div> <div class="guides-section"> <dt>Extending Rails</dt> <dd><a href="rails_on_rack.html">Rails on Rack</a></dd> <dd><a href="generators.html">Creating and Customizing Rails Generators & Templates</a></dd> </div> <div class="guides-section"> <dt>Contributing</dt> <dd><a href="contributing_to_ruby_on_rails.html">Contributing to Ruby on Rails</a></dd> <dd><a href="api_documentation_guidelines.html">API Documentation Guidelines</a></dd> <dd><a href="ruby_on_rails_guides_guidelines.html">Guides Guidelines</a></dd> <dd><a href="development_dependencies_install.html">Installing Rails Core Development Dependencies</a></dd> </div> <div class="guides-section"> <dt>Policies</dt> <dd><a href="maintenance_policy.html">Maintenance Policy</a></dd> </div> <div class="guides-section"> <dt>Release Notes</dt> <dd><a href="upgrading_ruby_on_rails.html">Upgrading Ruby on Rails</a></dd> <dd><a href="8_0_release_notes.html">Version 8.0 - November 2024</a></dd> <dd><a href="7_2_release_notes.html">Version 7.2 - August 2024</a></dd> <dd><a href="7_1_release_notes.html">Version 7.1 - October 2023</a></dd> <dd><a href="7_0_release_notes.html">Version 7.0 - December 2021</a></dd> <dd><a href="6_1_release_notes.html">Version 6.1 - December 2020</a></dd> <dd><a href="6_0_release_notes.html">Version 6.0 - August 2019</a></dd> <dd><a href="5_2_release_notes.html">Version 5.2 - April 2018</a></dd> <dd><a href="5_1_release_notes.html">Version 5.1 - April 2017</a></dd> <dd><a href="5_0_release_notes.html">Version 5.0 - June 2016</a></dd> <dd><a href="4_2_release_notes.html">Version 4.2 - December 2014</a></dd> <dd><a href="4_1_release_notes.html">Version 4.1 - April 2014</a></dd> <dd><a href="4_0_release_notes.html">Version 4.0 - June 2013</a></dd> <dd><a href="3_2_release_notes.html">Version 3.2 - January 2012</a></dd> <dd><a href="3_1_release_notes.html">Version 3.1 - August 2011</a></dd> <dd><a href="3_0_release_notes.html">Version 3.0 - August 2010</a></dd> <dd><a href="2_3_release_notes.html">Version 2.3 - March 2009</a></dd> <dd><a href="2_2_release_notes.html">Version 2.2 - November 2008</a></dd> </div> </dl> </div> </li> <li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribute</a></li> <li class="guides-index guides-index-small js-only"> <label for="guides-selector"> Navigate to a guide: </label> <select id="guides-selector" class="guides-index-item nav-item"> <option value="index.html">Guides Index</option> <optgroup label="Start Here"> <option value="getting_started.html">Getting Started with Rails</option> <option value="install_ruby_on_rails.html">Install Ruby on Rails</option> </optgroup> <optgroup label="Models"> <option value="active_record_basics.html">Active Record Basics</option> <option value="active_record_migrations.html">Active Record Migrations</option> <option value="active_record_validations.html">Active Record Validations</option> <option value="active_record_callbacks.html">Active Record Callbacks</option> <option value="association_basics.html">Active Record Associations</option> <option value="active_record_querying.html">Active Record Query Interface</option> <option value="active_model_basics.html">Active Model Basics</option> </optgroup> <optgroup label="Views"> <option value="action_view_overview.html">Action View Overview</option> <option value="layouts_and_rendering.html">Layouts and Rendering in Rails</option> <option value="action_view_helpers.html">Action View Helpers</option> <option value="form_helpers.html">Action View Form Helpers</option> </optgroup> <optgroup label="Controllers"> <option value="action_controller_overview.html">Action Controller Overview</option> <option value="action_controller_advanced_topics.html">Action Controller Advanced Topics</option> <option value="routing.html">Rails Routing from the Outside In</option> </optgroup> <optgroup label="Other Components"> <option value="active_support_core_extensions.html">Active Support Core Extensions</option> <option value="action_mailer_basics.html">Action Mailer Basics</option> <option value="action_mailbox_basics.html">Action Mailbox Basics</option> <option value="action_text_overview.html">Action Text Overview</option> <option value="active_job_basics.html">Active Job Basics</option> <option value="active_storage_overview.html">Active Storage Overview</option> <option value="action_cable_overview.html">Action Cable Overview</option> </optgroup> <optgroup label="Digging Deeper"> <option value="i18n.html">Rails Internationalization (I18n) API</option> <option value="testing.html">Testing Rails Applications</option> <option value="debugging_rails_applications.html">Debugging Rails Applications</option> <option value="configuring.html">Configuring Rails Applications</option> <option value="command_line.html">The Rails Command Line</option> <option value="asset_pipeline.html">The Asset Pipeline</option> <option value="working_with_javascript_in_rails.html">Working with JavaScript in Rails</option> <option value="autoloading_and_reloading_constants.html">Autoloading and Reloading</option> <option value="api_app.html">Using Rails for API-only Applications</option> </optgroup> <optgroup label="Going to Production"> <option value="tuning_performance_for_deployment.html">Tuning Performance for Deployment</option> <option value="caching_with_rails.html">Caching with Rails: An Overview</option> <option value="security.html">Securing Rails Applications</option> <option value="error_reporting.html">Error Reporting in Rails Applications</option> </optgroup> <optgroup label="Advanced Active Record"> <option value="active_record_multiple_databases.html">Multiple Databases</option> <option value="active_record_composite_primary_keys.html">Composite Primary Keys</option> </optgroup> <optgroup label="Extending Rails"> <option value="rails_on_rack.html">Rails on Rack</option> <option value="generators.html">Creating and Customizing Rails Generators & Templates</option> </optgroup> <optgroup label="Contributing"> <option value="contributing_to_ruby_on_rails.html">Contributing to Ruby on Rails</option> <option value="api_documentation_guidelines.html">API Documentation Guidelines</option> <option value="ruby_on_rails_guides_guidelines.html">Guides Guidelines</option> <option value="development_dependencies_install.html">Installing Rails Core Development Dependencies</option> </optgroup> <optgroup label="Policies"> <option value="maintenance_policy.html">Maintenance Policy</option> </optgroup> <optgroup label="Release Notes"> <option value="upgrading_ruby_on_rails.html">Upgrading Ruby on Rails</option> <option value="8_0_release_notes.html">Version 8.0 - November 2024</option> <option value="7_2_release_notes.html">Version 7.2 - August 2024</option> <option value="7_1_release_notes.html">Version 7.1 - October 2023</option> <option value="7_0_release_notes.html">Version 7.0 - December 2021</option> <option value="6_1_release_notes.html">Version 6.1 - December 2020</option> <option value="6_0_release_notes.html">Version 6.0 - August 2019</option> <option value="5_2_release_notes.html">Version 5.2 - April 2018</option> <option value="5_1_release_notes.html">Version 5.1 - April 2017</option> <option value="5_0_release_notes.html">Version 5.0 - June 2016</option> <option value="4_2_release_notes.html">Version 4.2 - December 2014</option> <option value="4_1_release_notes.html">Version 4.1 - April 2014</option> <option value="4_0_release_notes.html">Version 4.0 - June 2013</option> <option value="3_2_release_notes.html">Version 3.2 - January 2012</option> <option value="3_1_release_notes.html">Version 3.1 - August 2011</option> <option value="3_0_release_notes.html">Version 3.0 - August 2010</option> <option value="2_3_release_notes.html">Version 2.3 - March 2009</option> <option value="2_2_release_notes.html">Version 2.2 - November 2008</option> </optgroup> </select> </li> </ul> </nav> </div> </header> <hr class="hide" /> <main id="main"> <article> <header id="feature"> <div class="wrapper"> <h1>Action Mailbox Basics</h1><p>This guide provides you with all you need to get started in receiving emails to your application.</p><p>After reading this guide, you will know:</p> <ul> <li>How to receive email within a Rails application.</li> <li>How to configure Action Mailbox.</li> <li>How to generate and route emails to a mailbox.</li> <li>How to test incoming emails.</li> </ul> <nav id="column-side" aria-label="Chapter" class="guide-index" data-turbo="false"> <a id="chapter-nav-skip-link" href="#article-body" class="skip-link"> Skip to article body </a> <h2 class="chapter"> <picture aria-hidden="true"> <!-- Using the `source` HTML tag to set the dark theme image --> <source srcset="images/icon_book-close-bookmark-1-wht.svg" media="(prefers-color-scheme: dark)" /> <img src="images/icon_book-close-bookmark-1.svg" alt="Chapter Icon" /> </picture> Chapters </h2> <ol class="chapters"> <li><a href="#what-is-action-mailbox-questionmark">What is Action Mailbox?</a></li> <li><a href="#setup">Setup</a></li> <li><a href="#ingress-configuration">Ingress Configuration</a> <ul> <li><a href="#exim">Exim</a></li> <li><a href="#mailgun">Mailgun</a></li> <li><a href="#mandrill">Mandrill</a></li> <li><a href="#postfix">Postfix</a></li> <li><a href="#postmark">Postmark</a></li> <li><a href="#qmail">Qmail</a></li> <li><a href="#sendgrid">SendGrid</a></li> </ul></li> <li><a href="#processing-incoming-email">Processing Incoming Email</a> <ul> <li><a href="#configure-routing">Configure Routing</a></li> <li><a href="#create-a-mailbox">Create a Mailbox</a></li> <li><a href="#process-email">Process Email</a></li> <li><a href="#inbound-email-status">Inbound Email Status</a></li> </ul></li> <li><a href="#example">Example</a></li> <li><a href="#local-development-and-testing">Local Development and Testing</a></li> <li><a href="#incineration-of-inboundemails">Incineration of InboundEmails</a></li> </ol> </nav> </div> </header> <div class="wrapper"> <div id="column-main"> <section id="article-body"> <h2 id="what-is-action-mailbox-questionmark"><a class="anchorlink" href="#what-is-action-mailbox-questionmark" data-turbo="false"><span>1</span> What is Action Mailbox?</a></h2><p>Action Mailbox routes incoming emails to controller-like mailboxes for processing in your Rails application. Action Mailbox is for receiving email, while <a href="action_mailer_basics.html">Action Mailer</a> is for <em>sending</em> them.</p><p>The inbound emails are routed asynchronously using <a href="active_job_basics.html">Active Job</a> to one or several dedicated mailboxes. These emails are turned into <a href="https://api.rubyonrails.org/v8.0.1/classes/ActionMailbox/InboundEmail.html"><code>InboundEmail</code></a> records using <a href="active_record_basics.html">Active Record</a>, which are capable of interacting directly with the rest of your domain model.</p><p><code>InboundEmail</code> records also provide lifecycle tracking, storage of the original email via <a href="active_storage_overview.html">Active Storage</a>, and responsible data handling with on-by-default <a href="#incineration-of-inboundemails">incineration</a>.</p><p>Action Mailbox ships with ingresses which enable your application to receive emails from external email providers such as Mailgun, Mandrill, Postmark, and SendGrid. You can also handle inbound emails directly via the built-in Exim, Postfix, and Qmail ingresses.</p><h2 id="setup"><a class="anchorlink" href="#setup" data-turbo="false"><span>2</span> Setup</a></h2><p>Action Mailbox has a few moving parts. First, you'll run the installer. Next, you'll choose and configure an ingress for handling incoming email. You're then ready to add Action Mailbox routing, create mailboxes, and start processing incoming emails.</p><p>To start, let's install Action Mailbox:</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>action_mailbox:install </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails action_mailbox:install ">Copy</button> </div> <p>This will create an <code>application_mailbox.rb</code> file and copy over migrations.</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>db:migrate </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails db:migrate ">Copy</button> </div> <p>This will run the Action Mailbox and Active Storage migrations.</p><p>The Action Mailbox table <code>action_mailbox_inbound_emails</code> stores incoming messages and their processing status.</p><p>At this point, you can start your Rails server and check out <code>http://localhost:3000/rails/conductor/action_mailbox/inbound_emails</code>. See <a href="#local-development-and-testing">Local Development and Testing</a> for more.</p><p>The next step is to configure an ingress in your Rails application to specify how incoming emails should be received.</p><h2 id="ingress-configuration"><a class="anchorlink" href="#ingress-configuration" data-turbo="false"><span>3</span> Ingress Configuration</a></h2><p>Configuring ingress involves setting up credentials and endpoint information for the chosen email service. Here are the steps for each of the supported ingresses.</p><h3 id="exim"><a class="anchorlink" href="#exim" data-turbo="false"><span>3.1</span> Exim</a></h3><p>Tell Action Mailbox to accept emails from an SMTP relay:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:relay</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :relay ">Copy</button> </div> <p>Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add the password to your application's encrypted credentials under <code>action_mailbox.ingress_password</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">ingress_password</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: ingress_password: ... ">Copy</button> </div> <p>Alternatively, provide the password in the <code>RAILS_INBOUND_EMAIL_PASSWORD</code> environment variable.</p><p>Configure Exim to pipe inbound emails to <code>bin/rails action_mailbox:ingress:exim</code>, providing the <code>URL</code> of the relay ingress and the <code>INGRESS_PASSWORD</code> you previously generated. If your application lived at <code>https://example.com</code>, the full command would look like this:</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>action_mailbox:ingress:exim <span class="nv">URL</span><span class="o">=</span>https://example.com/rails/action_mailbox/relay/inbound_emails <span class="nv">INGRESS_PASSWORD</span><span class="o">=</span>... </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails action_mailbox:ingress:exim URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=... ">Copy</button> </div> <h3 id="mailgun"><a class="anchorlink" href="#mailgun" data-turbo="false"><span>3.2</span> Mailgun</a></h3><p>Give Action Mailbox your Mailgun Signing key (which you can find under Settings -> Security & Users -> API security in Mailgun), so it can authenticate requests to the Mailgun ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add your Signing key to your application's encrypted credentials under <code>action_mailbox.mailgun_signing_key</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">mailgun_signing_key</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: mailgun_signing_key: ... ">Copy</button> </div> <p>Alternatively, provide your Signing key in the <code>MAILGUN_INGRESS_SIGNING_KEY</code> environment variable.</p><p>Tell Action Mailbox to accept emails from Mailgun:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:mailgun</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :mailgun ">Copy</button> </div> <p><a href="https://documentation.mailgun.com/docs/mailgun/user-manual/receive-forward-store/">Configure Mailgun</a> to forward inbound emails to <code>/rails/action_mailbox/mailgun/inbound_emails/mime</code>. If your application lived at <code>https://example.com</code>, you would specify the fully-qualified URL <code>https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime</code>.</p><h3 id="mandrill"><a class="anchorlink" href="#mandrill" data-turbo="false"><span>3.3</span> Mandrill</a></h3><p>Give Action Mailbox your Mandrill API key, so it can authenticate requests to the Mandrill ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add your API key to your application's encrypted credentials under <code>action_mailbox.mandrill_api_key</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">mandrill_api_key</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: mandrill_api_key: ... ">Copy</button> </div> <p>Alternatively, provide your API key in the <code>MANDRILL_INGRESS_API_KEY</code> environment variable.</p><p>Tell Action Mailbox to accept emails from Mandrill:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:mandrill</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :mandrill ">Copy</button> </div> <p><a href="https://mandrill.zendesk.com/hc/en-us/articles/205583197-Inbound-Email-Processing-Overview">Configure Mandrill</a> to route inbound emails to <code>/rails/action_mailbox/mandrill/inbound_emails</code>. If your application lived at <code>https://example.com</code>, you would specify the fully-qualified URL <code>https://example.com/rails/action_mailbox/mandrill/inbound_emails</code>.</p><h3 id="postfix"><a class="anchorlink" href="#postfix" data-turbo="false"><span>3.4</span> Postfix</a></h3><p>Tell Action Mailbox to accept emails from an SMTP relay:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:relay</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :relay ">Copy</button> </div> <p>Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add the password to your application's encrypted credentials under <code>action_mailbox.ingress_password</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">ingress_password</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: ingress_password: ... ">Copy</button> </div> <p>Alternatively, provide the password in the <code>RAILS_INBOUND_EMAIL_PASSWORD</code> environment variable.</p><p><a href="https://serverfault.com/questions/258469/how-to-configure-postfix-to-pipe-all-incoming-email-to-a-script">Configure Postfix</a> to pipe inbound emails to <code>bin/rails action_mailbox:ingress:postfix</code>, providing the <code>URL</code> of the Postfix ingress and the <code>INGRESS_PASSWORD</code> you previously generated. If your application lived at <code>https://example.com</code>, the full command would look like this:</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>action_mailbox:ingress:postfix <span class="nv">URL</span><span class="o">=</span>https://example.com/rails/action_mailbox/relay/inbound_emails <span class="nv">INGRESS_PASSWORD</span><span class="o">=</span>... </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=... ">Copy</button> </div> <h3 id="postmark"><a class="anchorlink" href="#postmark" data-turbo="false"><span>3.5</span> Postmark</a></h3><p>Tell Action Mailbox to accept emails from Postmark:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:postmark</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :postmark ">Copy</button> </div> <p>Generate a strong password that Action Mailbox can use to authenticate requests to the Postmark ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add the password to your application's encrypted credentials under <code>action_mailbox.ingress_password</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">ingress_password</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: ingress_password: ... ">Copy</button> </div> <p>Alternatively, provide the password in the <code>RAILS_INBOUND_EMAIL_PASSWORD</code> environment variable.</p><p><a href="https://postmarkapp.com/manual#configure-your-inbound-webhook-url">Configure Postmark inbound webhook</a> to forward inbound emails to <code>/rails/action_mailbox/postmark/inbound_emails</code> with the username <code>actionmailbox</code> and the password you previously generated. If your application lived at <code>https://example.com</code>, you would configure Postmark with the following fully-qualified URL:</p><div class="interstitial code"> <pre><code class="highlight plaintext">https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/postmark/inbound_emails </code></pre> <button class="clipboard-button" data-clipboard-text="https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/postmark/inbound_emails ">Copy</button> </div> <div class="interstitial note"><p>When configuring your Postmark inbound webhook, be sure to check the box labeled <strong>"Include raw email content in JSON payload"</strong>. Action Mailbox needs the raw email content to work.</p></div><h3 id="qmail"><a class="anchorlink" href="#qmail" data-turbo="false"><span>3.6</span> Qmail</a></h3><p>Tell Action Mailbox to accept emails from an SMTP relay:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:relay</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :relay ">Copy</button> </div> <p>Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add the password to your application's encrypted credentials under <code>action_mailbox.ingress_password</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">ingress_password</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: ingress_password: ... ">Copy</button> </div> <p>Alternatively, provide the password in the <code>RAILS_INBOUND_EMAIL_PASSWORD</code> environment variable.</p><p>Configure Qmail to pipe inbound emails to <code>bin/rails action_mailbox:ingress:qmail</code>, providing the <code>URL</code> of the relay ingress and the <code>INGRESS_PASSWORD</code> you previously generated. If your application lived at <code>https://example.com</code>, the full command would look like this:</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>action_mailbox:ingress:qmail <span class="nv">URL</span><span class="o">=</span>https://example.com/rails/action_mailbox/relay/inbound_emails <span class="nv">INGRESS_PASSWORD</span><span class="o">=</span>... </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails action_mailbox:ingress:qmail URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=... ">Copy</button> </div> <h3 id="sendgrid"><a class="anchorlink" href="#sendgrid" data-turbo="false"><span>3.7</span> SendGrid</a></h3><p>Tell Action Mailbox to accept emails from SendGrid:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/environments/production.rb</span> <span class="n">config</span><span class="p">.</span><span class="nf">action_mailbox</span><span class="p">.</span><span class="nf">ingress</span> <span class="o">=</span> <span class="ss">:sendgrid</span> </code></pre> <button class="clipboard-button" data-clipboard-text="config.action_mailbox.ingress = :sendgrid ">Copy</button> </div> <p>Generate a strong password that Action Mailbox can use to authenticate requests to the SendGrid ingress.</p><p>Use <code>bin/rails credentials:edit</code> to add the password to your application's encrypted credentials under <code>action_mailbox.ingress_password</code>, where Action Mailbox will automatically find it:</p><div class="interstitial code"> <pre><code class="highlight yaml"><span class="na">action_mailbox</span><span class="pi">:</span> <span class="na">ingress_password</span><span class="pi">:</span> <span class="s">...</span> </code></pre> <button class="clipboard-button" data-clipboard-text="action_mailbox: ingress_password: ... ">Copy</button> </div> <p>Alternatively, provide the password in the <code>RAILS_INBOUND_EMAIL_PASSWORD</code> environment variable.</p><p><a href="https://sendgrid.com/docs/for-developers/parsing-email/setting-up-the-inbound-parse-webhook/">Configure SendGrid Inbound Parse</a> to forward inbound emails to <code>/rails/action_mailbox/sendgrid/inbound_emails</code> with the username <code>actionmailbox</code> and the password you previously generated. If your application lived at <code>https://example.com</code>, you would configure SendGrid with the following URL:</p><div class="interstitial code"> <pre><code class="highlight plaintext">https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/inbound_emails </code></pre> <button class="clipboard-button" data-clipboard-text="https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/inbound_emails ">Copy</button> </div> <div class="interstitial note"><p>When configuring your SendGrid Inbound Parse webhook, be sure to check the box labeled <strong>“Post the raw, full MIME message.”</strong> Action Mailbox needs the raw MIME message to work.</p></div><h2 id="processing-incoming-email"><a class="anchorlink" href="#processing-incoming-email" data-turbo="false"><span>4</span> Processing Incoming Email</a></h2><p>Processing incoming emails usually entails using the email content to create models, update views, queue background work, etc. in your Rails application.</p><p>Before you can start processing incoming emails, you'll need to setup Action Mailbox routing and create mailboxes.</p><h3 id="configure-routing"><a class="anchorlink" href="#configure-routing" data-turbo="false"><span>4.1</span> Configure Routing</a></h3><p>After an incoming email is received via the configured ingress, it needs to be forwarded to a mailbox for actual processing by your application. Much like the <a href="routing.html">Rails router</a> that dispatches URLs to controllers, routing in Action Mailbox defines which emails go to which mailboxes for processing. Routes are added to the <code>application_mailbox.rb</code> file using regular expressions:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># app/mailboxes/application_mailbox.rb</span> <span class="k">class</span> <span class="nc">ApplicationMailbox</span> <span class="o"><</span> <span class="no">ActionMailbox</span><span class="o">::</span><span class="no">Base</span> <span class="n">routing</span><span class="p">(</span><span class="sr">/^save@/i</span> <span class="o">=></span> <span class="ss">:forwards</span><span class="p">)</span> <span class="n">routing</span><span class="p">(</span><span class="sr">/@replies\./i</span> <span class="o">=></span> <span class="ss">:replies</span><span class="p">)</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class ApplicationMailbox < ActionMailbox::Base routing(/^save@/i => :forwards) routing(/@replies\./i => :replies) end ">Copy</button> </div> <p>The regular expression matches the incoming email's <code>to</code>, <code>cc</code>, or <code>bcc</code> fields. For example, the above will match any email sent to <code>save@</code> to a "forwards" mailbox. There are other ways to route an email, see <a href="https://api.rubyonrails.org/v8.0.1/classes/ActionMailbox/Base.html"><code>ActionMailbox::Base</code></a> for more.</p><p>We need to create that "forwards" mailbox next.</p><h3 id="create-a-mailbox"><a class="anchorlink" href="#create-a-mailbox" data-turbo="false"><span>4.2</span> Create a Mailbox</a></h3><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">#</span><span class="w"> </span>Generate new mailbox <span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate mailbox forwards </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails generate mailbox forwards ">Copy</button> </div> <p>This creates <code>app/mailboxes/forwards_mailbox.rb</code>, with a <code>ForwardsMailbox</code> class and a <code>process</code> method.</p><h3 id="process-email"><a class="anchorlink" href="#process-email" data-turbo="false"><span>4.3</span> Process Email</a></h3><p>When processing an <code>InboundEmail</code>, you can get the parsed version of the email as a <a href="https://github.com/mikel/mail"><code>Mail</code></a> object with <code>InboundEmail#mail</code>. You can also get the raw source directly using the <code>#source</code> method. With the <code>Mail</code> object, you can access the relevant fields, such as <code>mail.to</code>, <code>mail.body.decoded</code>, etc.</p><div class="interstitial code"> <pre><code class="highlight irb"><span class="gp">irb></span><span class="w"> </span><span class="n">mail</span> <span class="gp">=> #<Mail::Message:33780, Multipart: false, Headers: <Date: Wed, 31 Jan 2024 22:18:40 -0600>, <From: someone@hey.com>, <To: save@example.com>, <Message-ID: <65bb1ba066830_50303a70397e@Bhumis-MacBook-Pro.local.mail>></span><span class="p">,</span> <span class="o"><</span><span class="no">In</span><span class="o">-</span><span class="no">Reply</span><span class="o">-</span><span class="no">To</span><span class="p">:</span> <span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="no">Subject</span><span class="p">:</span> <span class="no">Hello</span> <span class="no">Action</span> <span class="no">Mailbox</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="no">Mime</span><span class="o">-</span><span class="no">Version</span><span class="p">:</span> <span class="mf">1.0</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="no">Content</span><span class="o">-</span><span class="no">Type</span><span class="p">:</span> <span class="n">text</span><span class="o">/</span><span class="n">plain</span><span class="p">;</span> <span class="n">charset</span><span class="o">=</span><span class="no">UTF</span><span class="o">-</span><span class="mi">8</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="no">Content</span><span class="o">-</span><span class="no">Transfer</span><span class="o">-</span><span class="no">Encoding</span><span class="p">:</span> <span class="mi">7</span><span class="n">bit</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="n">x</span><span class="o">-</span><span class="n">original</span><span class="o">-</span><span class="ss">to: </span><span class="o">>></span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">to</span> <span class="p">=></span> <span class="p">[</span><span class="s2">"save@example.com"</span><span class="p">]</span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">from</span> <span class="p">=></span> <span class="p">[</span><span class="s2">"someone@hey.com"</span><span class="p">]</span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">date</span> <span class="p">=></span> <span class="no">Wed</span><span class="p">,</span> <span class="mi">31</span> <span class="no">Jan</span> <span class="mi">2024</span> <span class="mi">22</span><span class="p">:</span><span class="mi">18</span><span class="p">:</span><span class="mi">40</span> <span class="o">-</span><span class="mo">0600</span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">subject</span> <span class="p">=></span> <span class="s2">"Hello Action Mailbox"</span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">body</span><span class="p">.</span><span class="nf">decoded</span> <span class="p">=></span> <span class="s2">"This is the body of the email message."</span> <span class="c"># mail.decoded, a shorthand for mail.body.decoded, also works</span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">decoded</span> <span class="p">=></span> <span class="s2">"This is the body of the email message."</span> <span class="gp">irb></span><span class="w"> </span><span class="n">mail</span><span class="p">.</span><span class="nf">body</span> <span class="gp">=> <Mail::Body:0x00007fc74cbf46c0 @boundary=nil, @preamble=nil, @epilogue=nil, @charset="US-ASCII", @part_sort_order=["text/plain", "text/enriched", "text/html", "multipart/alternative"], @parts=[], @raw_source="This is the body of the email message.", @ascii_only=true, @encoding="7bit"></span> </code></pre> <button class="clipboard-button" data-clipboard-text="mail mail.to mail.from mail.date mail.subject mail.body.decoded mail.decoded mail.body ">Copy</button> </div> <h3 id="inbound-email-status"><a class="anchorlink" href="#inbound-email-status" data-turbo="false"><span>4.4</span> Inbound Email Status</a></h3><p>While the email is being routed to a matching mailbox and processed, Action Mailbox updates the email status stored in <code>action_mailbox_inbound_emails</code> table with one of the following values:</p> <ul> <li><code>pending</code>: Received by one of the ingress controllers and scheduled for routing.</li> <li><code>processing</code>: During active processing, while a specific mailbox is running its <code>process</code> method.</li> <li><code>delivered</code>: Successfully processed by the specific mailbox.</li> <li><code>failed</code>: An exception was raised during the specific mailbox’s execution of the <code>process</code> method.</li> <li><code>bounced</code>: Rejected processing by the specific mailbox and bounced to sender.</li> </ul> <p>If the email is marked either <code>delivered</code>, <code>failed</code>, or <code>bounced</code> it's considered "processed" and marked for <a href="#incineration-of-inboundemails">incineration</a>.</p><h2 id="example"><a class="anchorlink" href="#example" data-turbo="false"><span>5</span> Example</a></h2><p>Here is an example of an Action Mailbox that processes emails to create "forwards" for the user's project.</p><p>The <code>before_processing</code> callback is used to ensure that certain conditions are met before <code>process</code> method is called. In this case, <code>before_processing</code> checks that the user has at least one project. Other supported <a href="https://api.rubyonrails.org/v8.0.1/classes/ActionMailbox/Callbacks.html">Action Mailbox callbacks</a> are <code>after_processing</code> and <code>around_processing</code>.</p><p>The email can be bounced using <code>bounced_with</code> if the "forwarder" has no projects. The "forwarder" is a <code>User</code> with the same email as <code>mail.from</code>.</p><p>If the "forwarder" does have at least one project, the <code>record_forward</code> method creates an Active Record model in the application using the email data <code>mail.subject</code> and <code>mail.decoded</code>. Otherwise, it sends an email, using Action Mailer, requesting the "forwarder" to choose a project.</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># app/mailboxes/forwards_mailbox.rb</span> <span class="k">class</span> <span class="nc">ForwardsMailbox</span> <span class="o"><</span> <span class="no">ApplicationMailbox</span> <span class="c1"># Callbacks specify prerequisites to processing</span> <span class="n">before_processing</span> <span class="ss">:require_projects</span> <span class="k">def</span> <span class="nf">process</span> <span class="c1"># Record the forward on the one project, or…</span> <span class="k">if</span> <span class="n">forwarder</span><span class="p">.</span><span class="nf">projects</span><span class="p">.</span><span class="nf">one?</span> <span class="n">record_forward</span> <span class="k">else</span> <span class="c1"># …involve a second Action Mailer to ask which project to forward into.</span> <span class="n">request_forwarding_project</span> <span class="k">end</span> <span class="k">end</span> <span class="kp">private</span> <span class="k">def</span> <span class="nf">require_projects</span> <span class="k">if</span> <span class="n">forwarder</span><span class="p">.</span><span class="nf">projects</span><span class="p">.</span><span class="nf">none?</span> <span class="c1"># Use Action Mailers to bounce incoming emails back to sender – this halts processing</span> <span class="n">bounce_with</span> <span class="no">Forwards</span><span class="o">::</span><span class="no">BounceMailer</span><span class="p">.</span><span class="nf">no_projects</span><span class="p">(</span><span class="n">inbound_email</span><span class="p">,</span> <span class="ss">forwarder: </span><span class="n">forwarder</span><span class="p">)</span> <span class="k">end</span> <span class="k">end</span> <span class="k">def</span> <span class="nf">record_forward</span> <span class="n">forwarder</span><span class="p">.</span><span class="nf">forwards</span><span class="p">.</span><span class="nf">create</span> <span class="ss">subject: </span><span class="n">mail</span><span class="p">.</span><span class="nf">subject</span><span class="p">,</span> <span class="ss">content: </span><span class="n">mail</span><span class="p">.</span><span class="nf">decoded</span> <span class="k">end</span> <span class="k">def</span> <span class="nf">request_forwarding_project</span> <span class="no">Forwards</span><span class="o">::</span><span class="no">RoutingMailer</span><span class="p">.</span><span class="nf">choose_project</span><span class="p">(</span><span class="n">inbound_email</span><span class="p">,</span> <span class="ss">forwarder: </span><span class="n">forwarder</span><span class="p">).</span><span class="nf">deliver_now</span> <span class="k">end</span> <span class="k">def</span> <span class="nf">forwarder</span> <span class="vi">@forwarder</span> <span class="o">||=</span> <span class="no">User</span><span class="p">.</span><span class="nf">find_by</span><span class="p">(</span><span class="ss">email_address: </span><span class="n">mail</span><span class="p">.</span><span class="nf">from</span><span class="p">)</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class ForwardsMailbox < ApplicationMailbox # Callbacks specify prerequisites to processing before_processing :require_projects def process # Record the forward on the one project, or… if forwarder.projects.one? record_forward else # …involve a second Action Mailer to ask which project to forward into. request_forwarding_project end end private def require_projects if forwarder.projects.none? # Use Action Mailers to bounce incoming emails back to sender – this halts processing bounce_with Forwards::BounceMailer.no_projects(inbound_email, forwarder: forwarder) end end def record_forward forwarder.forwards.create subject: mail.subject, content: mail.decoded end def request_forwarding_project Forwards::RoutingMailer.choose_project(inbound_email, forwarder: forwarder).deliver_now end def forwarder @forwarder ||= User.find_by(email_address: mail.from) end end ">Copy</button> </div> <h2 id="local-development-and-testing"><a class="anchorlink" href="#local-development-and-testing" data-turbo="false"><span>6</span> Local Development and Testing</a></h2><p>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 <code>/rails/conductor/action_mailbox/inbound_emails</code>, 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.</p><p>Here is and example of testing an inbound email with Action Mailbox TestHelpers.</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">ForwardsMailboxTest</span> <span class="o"><</span> <span class="no">ActionMailbox</span><span class="o">::</span><span class="no">TestCase</span> <span class="nb">test</span> <span class="s2">"directly recording a client forward for a forwarder and forwardee corresponding to one project"</span> <span class="k">do</span> <span class="n">assert_difference</span> <span class="o">-></span> <span class="p">{</span> <span class="n">people</span><span class="p">(</span><span class="ss">:david</span><span class="p">).</span><span class="nf">buckets</span><span class="p">.</span><span class="nf">first</span><span class="p">.</span><span class="nf">recordings</span><span class="p">.</span><span class="nf">count</span> <span class="p">}</span> <span class="k">do</span> <span class="n">receive_inbound_email_from_mail</span> <span class="p">\</span> <span class="ss">to: </span><span class="s2">"save@example.com"</span><span class="p">,</span> <span class="ss">from: </span><span class="n">people</span><span class="p">(</span><span class="ss">:david</span><span class="p">).</span><span class="nf">email_address</span><span class="p">,</span> <span class="ss">subject: </span><span class="s2">"Fwd: Status update?"</span><span class="p">,</span> <span class="ss">body: </span><span class="o"><<~</span><span class="no">BODY</span> <span class="sh"> --- Begin forwarded message ---</span> <span class="sh"> From: Frank Holland <frank@microsoft.com></span> <span class="sh"> What's the status?</span> <span class="no"> BODY</span> <span class="k">end</span> <span class="n">recording</span> <span class="o">=</span> <span class="n">people</span><span class="p">(</span><span class="ss">:david</span><span class="p">).</span><span class="nf">buckets</span><span class="p">.</span><span class="nf">first</span><span class="p">.</span><span class="nf">recordings</span><span class="p">.</span><span class="nf">last</span> <span class="n">assert_equal</span> <span class="n">people</span><span class="p">(</span><span class="ss">:david</span><span class="p">),</span> <span class="n">recording</span><span class="p">.</span><span class="nf">creator</span> <span class="n">assert_equal</span> <span class="s2">"Status update?"</span><span class="p">,</span> <span class="n">recording</span><span class="p">.</span><span class="nf">forward</span><span class="p">.</span><span class="nf">subject</span> <span class="n">assert_match</span> <span class="s2">"What's the status?"</span><span class="p">,</span> <span class="n">recording</span><span class="p">.</span><span class="nf">forward</span><span class="p">.</span><span class="nf">content</span><span class="p">.</span><span class="nf">to_s</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class ForwardsMailboxTest < ActionMailbox::TestCase test "directly recording a client forward for a forwarder and forwardee corresponding to one project" do assert_difference -> { people(:david).buckets.first.recordings.count } do receive_inbound_email_from_mail \ to: "save@example.com", from: people(:david).email_address, subject: "Fwd: Status update?", body: <<~BODY --- Begin forwarded message --- From: Frank Holland <frank@microsoft.com> What's the status? BODY end recording = people(:david).buckets.first.recordings.last assert_equal people(:david), recording.creator assert_equal "Status update?", recording.forward.subject assert_match "What's the status?", recording.forward.content.to_s end end ">Copy</button> </div> <p>Please refer to the <a href="https://api.rubyonrails.org/v8.0.1/classes/ActionMailbox/TestHelper.html">ActionMailbox::TestHelper API</a> for further test helper methods.</p><h2 id="incineration-of-inboundemails"><a class="anchorlink" href="#incineration-of-inboundemails" data-turbo="false"><span>7</span> Incineration of InboundEmails</a></h2><p>By default, an <code>InboundEmail</code> that has been processed will be incinerated after 30 days. The <code>InboundEmail</code> is considered as processed when its status changes to <code>delivered</code>, <code>failed</code>, or <code>bounced</code>.</p><p>The actual incineration is done via the <a href="https://api.rubyonrails.org/v8.0.1/classes/ActionMailbox/IncinerationJob.html"><code>IncinerationJob</code></a> that's scheduled to run after <a href="configuring.html#config-action-mailbox-incinerate-after"><code>config.action_mailbox.incinerate_after</code></a> time. This value is set to <code>30.days</code> by default, 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.)</p><p>Default data incineration ensures that you're not holding on to people's data unnecessarily after they may have canceled their accounts or deleted their content.</p><p>The intention with Action Mailbox processing is that as you process an email, you should extract all the data you need from the email and persist it into domain models in your application. The <code>InboundEmail</code> stays in the system for the configured time to allow for debugging and forensics and then will be deleted.</p> </section> <hr> <footer aria-labelledby="heading-feedback" role="region"> <h2 id="heading-feedback">Feedback</h2> <p> You're encouraged to help improve the quality of this guide. </p> <p> Please contribute if you see any typos or factual errors. To get started, you can read our <a href="https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation">documentation contributions</a> section. </p> <p> You may also find incomplete content or stuff that is not up to date. Please do add any missing documentation for main. Make sure to check <a href="https://edgeguides.rubyonrails.org">Edge Guides</a> first to verify if the issues are already fixed or not on the main branch. Check the <a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails Guides Guidelines</a> for style and conventions. </p> <p> If for whatever reason you spot something to fix but cannot patch it yourself, please <a href="https://github.com/rails/rails/issues">open an issue</a>. </p> <p>And last but not least, any kind of discussion regarding Ruby on Rails documentation is very welcome on the <a href="https://discuss.rubyonrails.org/c/rubyonrails-docs">official Ruby on Rails Forum</a>. </p> </footer> </div> </article> </main> <hr class="hide" /> <footer id="complementary"> <div class="wrapper"> <p>This work is licensed under a <a href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International</a> License</p> <p>"Rails", "Ruby on Rails", and the Rails logo are trademarks of David Heinemeier Hansson. All rights reserved.</p> </div> </footer> <a href="#main-skip-link" class="back-to-top" data-turbo="false"><span class="visibly-hidden">Back to top</span></a> </body> </html>