Add Exim and Qmail support to Action Mailbox

This commit is contained in:
George Claghorn 2019-01-12 21:38:26 -05:00 committed by GitHub
parent bb75d68fe2
commit 512b5316dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 196 additions and 68 deletions

View File

@ -1,6 +1,6 @@
# Action Mailbox
Action Mailbox routes incoming emails to controller-like mailboxes for processing in Rails. It ships with ingresses for Amazon SES, Mailgun, Mandrill, Postmark, and SendGrid. You can also handle inbound mails directly via the built-in Postfix ingress.
Action Mailbox routes incoming emails to controller-like mailboxes for processing in Rails. It ships with ingresses for Amazon SES, Mailgun, Mandrill, Postmark, and SendGrid. You can also handle inbound mails directly via the built-in Exim, Postfix, and Qmail ingresses.
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.

View File

@ -1,31 +1,31 @@
# frozen_string_literal: true
module ActionMailbox
# Ingests inbound emails relayed from Postfix.
# Ingests inbound emails relayed from an SMTP server.
#
# Authenticates requests using HTTP basic access authentication. The username is always +actionmailbox+, and the
# password is read from the application's encrypted credentials or an environment variable. See the Usage section below.
#
# Note that basic authentication is insecure over unencrypted HTTP. An attacker that intercepts cleartext requests to
# the Postfix ingress can learn its password. You should only use the Postfix ingress over HTTPS.
# the ingress can learn its password. You should only use this ingress over HTTPS.
#
# Returns:
#
# - <tt>204 No Content</tt> if an inbound email is successfully recorded and enqueued for routing to the appropriate mailbox
# - <tt>401 Unauthorized</tt> if the request could not be authenticated
# - <tt>404 Not Found</tt> if Action Mailbox is not configured to accept inbound emails from Postfix
# - <tt>404 Not Found</tt> if Action Mailbox is not configured to accept inbound emails relayed from an SMTP server
# - <tt>415 Unsupported Media Type</tt> if the request does not contain an RFC 822 message
# - <tt>500 Server Error</tt> if the ingress password is not configured, or if one of the Active Record database,
# the Active Storage service, or the Active Job backend is misconfigured or unavailable
#
# == Usage
#
# 1. Tell Action Mailbox to accept emails from Postfix:
# 1. Tell Action Mailbox to accept emails from an SMTP relay:
#
# # config/environments/production.rb
# config.action_mailbox.ingress = :postfix
# config.action_mailbox.ingress = :relay
#
# 2. Generate a strong password that Action Mailbox can use to authenticate requests to the Postfix ingress.
# 2. Generate a strong password that Action Mailbox can use to authenticate requests to the ingress.
#
# Use <tt>rails credentials:edit</tt> to add the password to your application's encrypted credentials under
# +action_mailbox.ingress_password+, where Action Mailbox will automatically find it:
@ -35,14 +35,20 @@ module ActionMailbox
#
# Alternatively, provide the password in the +RAILS_INBOUND_EMAIL_PASSWORD+ environment variable.
#
# 3. {Configure Postfix}[https://serverfault.com/questions/258469/how-to-configure-postfix-to-pipe-all-incoming-email-to-a-script]
# to pipe inbound emails to <tt>bin/rails action_mailbox:ingress:postfix</tt>, providing the +URL+ of the Postfix
# ingress and the +INGRESS_PASSWORD+ you previously generated.
# 3. Configure your SMTP server to pipe inbound emails to the appropriate ingress command, providing the +URL+ of the
# relay ingress and the +INGRESS_PASSWORD+ you previously generated.
#
# If your application lived at <tt>https://example.com</tt>, the full command would look like this:
# If your application lives at <tt>https://example.com</tt>, you would configure the Postfix SMTP server to pipe
# inbound emails to the following command:
#
# URL=https://example.com/rails/action_mailbox/postfix/inbound_emails INGRESS_PASSWORD=... bin/rails action_mailbox:ingress:postfix
class Ingresses::Postfix::InboundEmailsController < ActionMailbox::BaseController
# bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/postfix/inbound_emails INGRESS_PASSWORD=...
#
# Built-in ingress commands are available for these popular SMTP servers:
#
# - Exim (<tt>bin/rails action_mailbox:ingress:exim)
# - Postfix (<tt>bin/rails action_mailbox:ingress:postfix)
# - Qmail (<tt>bin/rails action_mailbox:ingress:qmail)
class Ingresses::Relay::InboundEmailsController < ActionMailbox::BaseController
before_action :authenticate_by_password, :require_valid_rfc822_message
def create

View File

@ -4,8 +4,8 @@ Rails.application.routes.draw do
scope "/rails/action_mailbox", module: "action_mailbox/ingresses" do
post "/amazon/inbound_emails" => "amazon/inbound_emails#create", as: :rails_amazon_inbound_emails
post "/mandrill/inbound_emails" => "mandrill/inbound_emails#create", as: :rails_mandrill_inbound_emails
post "/postfix/inbound_emails" => "postfix/inbound_emails#create", as: :rails_postfix_inbound_emails
post "/postmark/inbound_emails" => "postmark/inbound_emails#create", as: :rails_postmark_inbound_emails
post "/relay/inbound_emails" => "relay/inbound_emails#create", as: :rails_relay_inbound_emails
post "/sendgrid/inbound_emails" => "sendgrid/inbound_emails#create", as: :rails_sendgrid_inbound_emails
# Mailgun requires that a webhook's URL end in 'mime' for it to receive the raw contents of emails.

View File

@ -5,19 +5,27 @@ require "net/http"
require "uri"
module ActionMailbox
class PostfixRelayer
class Result < Struct.new(:output)
class Relayer
class Result < Struct.new(:status_code, :message)
def success?
!failure?
end
def failure?
output.match?(/\A[45]\.\d{1,3}\.\d{1,3}(\s|\z)/)
transient_failure? || permanent_failure?
end
def transient_failure?
status_code.start_with?("4.")
end
def permanent_failure?
status_code.start_with?("5.")
end
end
CONTENT_TYPE = "message/rfc822"
USER_AGENT = "Action Mailbox Postfix relayer v#{ActionMailbox.version}"
USER_AGENT = "Action Mailbox relayer v#{ActionMailbox.version}"
attr_reader :uri, :username, :password
@ -28,18 +36,18 @@ module ActionMailbox
def relay(source)
case response = post(source)
when Net::HTTPSuccess
Result.new "2.0.0 Successfully relayed message to Postfix ingress"
Result.new "2.0.0", "Successfully relayed message to ingress"
when Net::HTTPUnauthorized
Result.new "4.7.0 Invalid credentials for Postfix ingress"
Result.new "4.7.0", "Invalid credentials for ingress"
else
Result.new "4.0.0 HTTP #{response.code}"
Result.new "4.0.0", "HTTP #{response.code}"
end
rescue IOError, SocketError, SystemCallError => error
Result.new "4.4.2 Network error relaying to Postfix ingress: #{error.message}"
Result.new "4.4.2", "Network error relaying to ingress: #{error.message}"
rescue Timeout::Error
Result.new "4.4.2 Timed out relaying to Postfix ingress"
Result.new "4.4.2", "Timed out relaying to ingress"
rescue => error
Result.new "4.0.0 Error relaying to Postfix ingress: #{error.message}"
Result.new "4.0.0", "Error relaying to ingress: #{error.message}"
end
private

View File

@ -2,12 +2,37 @@
namespace :action_mailbox do
namespace :ingress do
desc "Pipe an inbound email from STDIN to the Postfix ingress (URL and INGRESS_PASSWORD required)"
task :postfix do
task :environment do
require "active_support"
require "active_support/core_ext/object/blank"
require "action_mailbox/postfix_relayer"
require "action_mailbox/relayer"
end
desc "Relay an inbound email from Exim to Action Mailbox (URL and INGRESS_PASSWORD required)"
task exim: "action_mailbox:ingress:environment" do
url, password = ENV.values_at("URL", "INGRESS_PASSWORD")
if url.blank? || password.blank?
print "URL and INGRESS_PASSWORD are required"
exit 64 # EX_USAGE
end
ActionMailbox::Relayer.new(url: url, password: password).relay(STDIN.read).tap do |result|
print result.message
case
when result.success?
exit 0
when result.transient_failure?
exit 75 # EX_TEMPFAIL
else
exit 69 # EX_UNAVAILABLE
end
end
end
desc "Relay an inbound email from Postfix to Action Mailbox (URL and INGRESS_PASSWORD required)"
task postfix: "action_mailbox:ingress:environment" do
url, password = ENV.values_at("URL", "INGRESS_PASSWORD")
if url.blank? || password.blank?
@ -15,10 +40,33 @@ namespace :action_mailbox do
exit 1
end
ActionMailbox::PostfixRelayer.new(url: url, password: password).relay(STDIN.read).tap do |result|
print result.output
ActionMailbox::Relayer.new(url: url, password: password).relay(STDIN.read).tap do |result|
print "#{result.status_code} #{result.message}"
exit result.success?
end
end
desc "Relay an inbound email from Qmail to Action Mailbox (URL and INGRESS_PASSWORD required)"
task qmail: "action_mailbox:ingress:environment" do
url, password = ENV.values_at("URL", "INGRESS_PASSWORD")
if url.blank? || password.blank?
print "URL and INGRESS_PASSWORD are required"
exit 111
end
ActionMailbox::Relayer.new(url: url, password: password).relay(STDIN.read).tap do |result|
print result.message
case
when result.success?
exit 0
when result.transient_failure?
exit 111
else
exit 100
end
end
end
end
end

View File

@ -2,12 +2,12 @@
require "test_helper"
class ActionMailbox::Ingresses::Postfix::InboundEmailsControllerTest < ActionDispatch::IntegrationTest
setup { ActionMailbox.ingress = :postfix }
class ActionMailbox::Ingresses::Relay::InboundEmailsControllerTest < ActionDispatch::IntegrationTest
setup { ActionMailbox.ingress = :relay }
test "receiving an inbound email from Postfix" do
test "receiving an inbound email relayed from an SMTP server" do
assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do
post rails_postfix_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" },
post rails_relay_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" },
params: file_fixture("../files/welcome.eml").read
end
@ -18,18 +18,18 @@ class ActionMailbox::Ingresses::Postfix::InboundEmailsControllerTest < ActionDis
assert_equal "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com", inbound_email.message_id
end
test "rejecting an unauthorized inbound email from Postfix" do
test "rejecting an unauthorized inbound email" do
assert_no_difference -> { ActionMailbox::InboundEmail.count } do
post rails_postfix_inbound_emails_url, headers: { "Content-Type" => "message/rfc822" },
post rails_relay_inbound_emails_url, headers: { "Content-Type" => "message/rfc822" },
params: file_fixture("../files/welcome.eml").read
end
assert_response :unauthorized
end
test "rejecting an inbound email of an unsupported media type from Postfix" do
test "rejecting an inbound email of an unsupported media type" do
assert_no_difference -> { ActionMailbox::InboundEmail.count } do
post rails_postfix_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "text/plain" },
post rails_relay_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "text/plain" },
params: file_fixture("../files/welcome.eml").read
end
@ -39,7 +39,7 @@ class ActionMailbox::Ingresses::Postfix::InboundEmailsControllerTest < ActionDis
test "raising when the configured password is nil" do
switch_password_to nil do
assert_raises ArgumentError do
post rails_postfix_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" },
post rails_relay_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" },
params: file_fixture("../files/welcome.eml").read
end
end
@ -48,7 +48,7 @@ class ActionMailbox::Ingresses::Postfix::InboundEmailsControllerTest < ActionDis
test "raising when the configured password is blank" do
switch_password_to "" do
assert_raises ArgumentError do
post rails_postfix_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" },
post rails_relay_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" },
params: file_fixture("../files/welcome.eml").read
end
end

View File

@ -2,35 +2,37 @@
require_relative "../test_helper"
require "action_mailbox/postfix_relayer"
require "action_mailbox/relayer"
module ActionMailbox
class PostfixRelayerTest < ActiveSupport::TestCase
URL = "https://example.com/rails/action_mailbox/postfix/inbound_emails"
class RelayerTest < ActiveSupport::TestCase
URL = "https://example.com/rails/action_mailbox/relay/inbound_emails"
INGRESS_PASSWORD = "secret"
setup do
@relayer = ActionMailbox::PostfixRelayer.new(url: URL, password: INGRESS_PASSWORD)
@relayer = ActionMailbox::Relayer.new(url: URL, password: INGRESS_PASSWORD)
end
test "successfully relaying an email" do
stub_request(:post, URL).to_return status: 204
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "2.0.0 Successfully relayed message to Postfix ingress", result.output
assert_equal "2.0.0", result.status_code
assert_equal "Successfully relayed message to ingress", result.message
assert result.success?
assert_not result.failure?
assert_requested :post, URL, body: file_fixture("welcome.eml").read,
basic_auth: [ "actionmailbox", INGRESS_PASSWORD ],
headers: { "Content-Type" => "message/rfc822", "User-Agent" => /\AAction Mailbox Postfix relayer v\d+\./ }
headers: { "Content-Type" => "message/rfc822", "User-Agent" => /\AAction Mailbox relayer v\d+\./ }
end
test "unsuccessfully relaying with invalid credentials" do
stub_request(:post, URL).to_return status: 401
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.7.0 Invalid credentials for Postfix ingress", result.output
assert_equal "4.7.0", result.status_code
assert_equal "Invalid credentials for ingress", result.message
assert_not result.success?
assert result.failure?
end
@ -39,7 +41,8 @@ module ActionMailbox
stub_request(:post, URL).to_return status: 500
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.0.0 HTTP 500", result.output
assert_equal "4.0.0", result.status_code
assert_equal "HTTP 500", result.message
assert_not result.success?
assert result.failure?
end
@ -48,7 +51,8 @@ module ActionMailbox
stub_request(:post, URL).to_return status: 504
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.0.0 HTTP 504", result.output
assert_equal "4.0.0", result.status_code
assert_equal "HTTP 504", result.message
assert_not result.success?
assert result.failure?
end
@ -57,7 +61,8 @@ module ActionMailbox
stub_request(:post, URL).to_raise Errno::ECONNRESET.new
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.4.2 Network error relaying to Postfix ingress: Connection reset by peer", result.output
assert_equal "4.4.2", result.status_code
assert_equal "Network error relaying to ingress: Connection reset by peer", result.message
assert_not result.success?
assert result.failure?
end
@ -66,7 +71,8 @@ module ActionMailbox
stub_request(:post, URL).to_raise SocketError.new("Failed to open TCP connection to example.com:443")
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.4.2 Network error relaying to Postfix ingress: Failed to open TCP connection to example.com:443", result.output
assert_equal "4.4.2", result.status_code
assert_equal "Network error relaying to ingress: Failed to open TCP connection to example.com:443", result.message
assert_not result.success?
assert result.failure?
end
@ -75,7 +81,8 @@ module ActionMailbox
stub_request(:post, URL).to_timeout
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.4.2 Timed out relaying to Postfix ingress", result.output
assert_equal "4.4.2", result.status_code
assert_equal "Timed out relaying to ingress", result.message
assert_not result.success?
assert result.failure?
end
@ -84,7 +91,8 @@ module ActionMailbox
stub_request(:post, URL).to_raise StandardError.new("Something went wrong")
result = @relayer.relay(file_fixture("welcome.eml").read)
assert_equal "4.0.0 Error relaying to Postfix ingress: Something went wrong", result.output
assert_equal "4.0.0", result.status_code
assert_equal "Error relaying to ingress: Something went wrong", result.message
assert_not result.success?
assert result.failure?
end

View File

@ -21,7 +21,7 @@ Introduction
Action Mailbox routes incoming emails to controller-like mailboxes for
processing in Rails. It ships with ingresses for Amazon SES, Mailgun, Mandrill,
Postmark, and SendGrid. You can also handle inbound mails directly via the
built-in Postfix ingress.
built-in Exim, Postfix, and Qmail ingresses.
The inbound emails are turned into `InboundEmail` records using Active Record
and feature lifecycle tracking, storage of the original email on cloud storage
@ -65,6 +65,36 @@ to deliver emails to your application via POST requests to
`https://example.com`, you would specify the fully-qualified URL
`https://example.com/rails/action_mailbox/amazon/inbound_emails`.
### Exim
Tell Action Mailbox to accept emails from an SMTP relay:
```ruby
# config/environments/production.rb
config.action_mailbox.ingress = :relay
```
Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress.
Use `rails credentials:edit` to add the password to your application's encrypted credentials under
`action_mailbox.ingress_password`, where Action Mailbox will automatically find it:
```yaml
action_mailbox:
ingress_password: ...
```
Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable.
Configure Exim to pipe inbound emails to `bin/rails action_mailbox:ingress:exim`,
providing the `URL` of the relay ingress and the `INGRESS_PASSWORD` you
previously generated. If your application lived at `https://example.com`, the
full command would look like this:
```shell
bin/rails action_mailbox:ingress:exim URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
```
### Mailgun
Give Action Mailbox your
@ -126,14 +156,14 @@ the fully-qualified URL `https://example.com/rails/action_mailbox/mandrill/inbou
### Postfix
Tell Action Mailbox to accept emails from Postfix:
Tell Action Mailbox to accept emails from an SMTP relay:
```ruby
# config/environments/production.rb
config.action_mailbox.ingress = :postfix
config.action_mailbox.ingress = :relay
```
Generate a strong password that Action Mailbox can use to authenticate requests to the Postfix ingress.
Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress.
Use `rails credentials:edit` to add the password to your application's encrypted credentials under
`action_mailbox.ingress_password`, where Action Mailbox will automatically find it:
@ -151,8 +181,8 @@ the `URL` of the Postfix ingress and the `INGRESS_PASSWORD` you previously
generated. If your application lived at `https://example.com`, the full command
would look like this:
```bash
$ URL=https://example.com/rails/action_mailbox/postfix/inbound_emails INGRESS_PASSWORD=... rails action_mailbox:ingress:postfix
```shell
$ bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
```
### Postmark
@ -191,6 +221,36 @@ https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/postmark/inbound
NOTE: When configuring your Postmark inbound webhook, be sure to check the box labeled **"Include raw email content in JSON payload"**.
Action Mailbox needs the raw email content to work.
### Qmail
Tell Action Mailbox to accept emails from an SMTP relay:
```ruby
# config/environments/production.rb
config.action_mailbox.ingress = :relay
```
Generate a strong password that Action Mailbox can use to authenticate requests to the relay ingress.
Use `rails credentials:edit` to add the password to your application's encrypted credentials under
`action_mailbox.ingress_password`, where Action Mailbox will automatically find it:
```yaml
action_mailbox:
ingress_password: ...
```
Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable.
Configure Qmail to pipe inbound emails to `bin/rails action_mailbox:ingress:qmail`,
providing the `URL` of the relay ingress and the `INGRESS_PASSWORD` you
previously generated. If your application lived at `https://example.com`, the
full command would look like this:
```shell
bin/rails action_mailbox:ingress:qmail URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
```
### SendGrid
Tell Action Mailbox to accept emails from SendGrid:

View File

@ -22,8 +22,8 @@ module ApplicationTests
cart GET /cart(.:format) cart#show
rails_amazon_inbound_emails POST /rails/action_mailbox/amazon/inbound_emails(.:format) action_mailbox/ingresses/amazon/inbound_emails#create
rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create
rails_postfix_inbound_emails POST /rails/action_mailbox/postfix/inbound_emails(.:format) action_mailbox/ingresses/postfix/inbound_emails#create
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create
rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create
rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create
rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index

View File

@ -26,7 +26,6 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase
PUT /post(.:format) posts#update
DELETE /post(.:format) posts#destroy
POST /post(.:format) posts#create
rails_postfix_inbound_emails POST /rails/action_mailbox/postfix/inbound_emails(.:format) action_mailbox/ingresses/postfix/inbound_emails#create
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
OUTPUT
@ -65,8 +64,8 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase
POST /cart(.:format) cart#create
rails_amazon_inbound_emails POST /rails/action_mailbox/amazon/inbound_emails(.:format) action_mailbox/ingresses/amazon/inbound_emails#create
rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create
rails_postfix_inbound_emails POST /rails/action_mailbox/postfix/inbound_emails(.:format) action_mailbox/ingresses/postfix/inbound_emails#create
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create
rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create
rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create
POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create
@ -141,7 +140,6 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase
PUT /admin/post(.:format) admin/posts#update
DELETE /admin/post(.:format) admin/posts#destroy
POST /admin/post(.:format) admin/posts#create
rails_postfix_inbound_emails POST /rails/action_mailbox/postfix/inbound_emails(.:format) action_mailbox/ingresses/postfix/inbound_emails#create
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
OUTPUT
@ -170,8 +168,8 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase
Prefix Verb URI Pattern Controller#Action
rails_amazon_inbound_emails POST /rails/action_mailbox/amazon/inbound_emails(.:format) action_mailbox/ingresses/amazon/inbound_emails#create
rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create
rails_postfix_inbound_emails POST /rails/action_mailbox/postfix/inbound_emails(.:format) action_mailbox/ingresses/postfix/inbound_emails#create
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create
rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create
rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create
rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index
@ -219,15 +217,15 @@ class Rails::Command::RoutesTest < ActiveSupport::TestCase
URI | /rails/action_mailbox/mandrill/inbound_emails(.:format)
Controller#Action | action_mailbox/ingresses/mandrill/inbound_emails#create
--[ Route 4 ]--------------
Prefix | rails_postfix_inbound_emails
Verb | POST
URI | /rails/action_mailbox/postfix/inbound_emails(.:format)
Controller#Action | action_mailbox/ingresses/postfix/inbound_emails#create
--[ Route 5 ]--------------
Prefix | rails_postmark_inbound_emails
Verb | POST
URI | /rails/action_mailbox/postmark/inbound_emails(.:format)
Controller#Action | action_mailbox/ingresses/postmark/inbound_emails#create
--[ Route 5 ]--------------
Prefix | rails_relay_inbound_emails
Verb | POST
URI | /rails/action_mailbox/relay/inbound_emails(.:format)
Controller#Action | action_mailbox/ingresses/relay/inbound_emails#create
--[ Route 6 ]--------------
Prefix | rails_sendgrid_inbound_emails
Verb | POST