aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailbox/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionmailbox/lib')
-rw-r--r--actionmailbox/lib/action_mailbox/base.rb31
-rw-r--r--actionmailbox/lib/action_mailbox/engine.rb7
-rw-r--r--actionmailbox/lib/action_mailbox/gem_version.rb2
-rw-r--r--actionmailbox/lib/action_mailbox/relayer.rb (renamed from actionmailbox/lib/action_mailbox/postfix_relayer.rb)28
-rw-r--r--actionmailbox/lib/action_mailbox/router/route.rb2
-rw-r--r--actionmailbox/lib/action_mailbox/routing.rb2
-rw-r--r--actionmailbox/lib/action_mailbox/test_case.rb2
-rw-r--r--actionmailbox/lib/action_mailbox/test_helper.rb12
-rw-r--r--actionmailbox/lib/rails/generators/mailbox/templates/application_mailbox.rb.tt2
-rw-r--r--actionmailbox/lib/rails/generators/mailbox/templates/mailbox.rb.tt2
-rw-r--r--actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt2
-rw-r--r--actionmailbox/lib/tasks/ingress.rake58
12 files changed, 106 insertions, 44 deletions
diff --git a/actionmailbox/lib/action_mailbox/base.rb b/actionmailbox/lib/action_mailbox/base.rb
index 76c3a4886c..ff8587acd1 100644
--- a/actionmailbox/lib/action_mailbox/base.rb
+++ b/actionmailbox/lib/action_mailbox/base.rb
@@ -7,7 +7,7 @@ require "action_mailbox/routing"
module ActionMailbox
# The base class for all application mailboxes. Not intended to be inherited from directly. Inherit from
- # `ApplicationMailbox` instead, as that's where the app-specific routing is configured. This routing
+ # +ApplicationMailbox+ instead, as that's where the app-specific routing is configured. This routing
# is specified in the following ways:
#
# class ApplicationMailbox < ActionMailbox::Base
@@ -27,15 +27,15 @@ module ActionMailbox
# routing :all => :backstop
# end
#
- # Application mailboxes need to overwrite the `#process` method, which is invoked by the framework after
- # callbacks have been run. The callbacks available are: `before_processing`, `after_processing`, and
- # `around_processing`. The primary use case is ensure certain preconditions to processing are fulfilled
- # using `before_processing` callbacks.
+ # Application mailboxes need to overwrite the +#process+ method, which is invoked by the framework after
+ # callbacks have been run. The callbacks available are: +before_processing+, +after_processing+, and
+ # +around_processing+. The primary use case is ensure certain preconditions to processing are fulfilled
+ # using +before_processing+ callbacks.
#
- # If a precondition fails to be met, you can halt the processing using the `#bounced!` method,
+ # If a precondition fails to be met, you can halt the processing using the +#bounced!+ method,
# which will silently prevent any further processing, but not actually send out any bounce notice. You
# can also pair this behavior with the invocation of an Action Mailer class responsible for sending out
- # an actual bounce email. This is done using the `#bounce_with` method, which takes the mail object returned
+ # an actual bounce email. This is done using the +#bounce_with+ method, which takes the mail object returned
# by an Action Mailer method, like so:
#
# class ForwardsMailbox < ApplicationMailbox
@@ -50,12 +50,12 @@ module ActionMailbox
# end
#
# During the processing of the inbound email, the status will be tracked. Before processing begins,
- # the email will normally have the `pending` status. Once processing begins, just before callbacks
- # and the `#process` method is called, the status is changed to `processing`. If processing is allowed to
- # complete, the status is changed to `delivered`. If a bounce is triggered, then `bounced`. If an unhandled
- # exception is bubbled up, then `failed`.
+ # the email will normally have the +pending+ status. Once processing begins, just before callbacks
+ # and the +#process+ method is called, the status is changed to +processing+. If processing is allowed to
+ # complete, the status is changed to +delivered+. If a bounce is triggered, then +bounced+. If an unhandled
+ # exception is bubbled up, then +failed+.
#
- # Exceptions can be handled at the class level using the familiar `Rescuable` approach:
+ # Exceptions can be handled at the class level using the familiar +Rescuable+ approach:
#
# class ForwardsMailbox < ApplicationMailbox
# rescue_from(ApplicationSpecificVerificationError) { bounced! }
@@ -77,7 +77,7 @@ module ActionMailbox
@inbound_email = inbound_email
end
- def perform_processing
+ def perform_processing #:nodoc:
track_status_of_inbound_email do
run_callbacks :process do
process
@@ -92,11 +92,12 @@ module ActionMailbox
# Overwrite in subclasses
end
- def finished_processing?
+ def finished_processing? #:nodoc:
inbound_email.delivered? || inbound_email.bounced?
end
+ # Enqueues the given +message+ for delivery and changes the inbound email's status to +:bounced+.
def bounce_with(message)
inbound_email.bounced!
message.deliver_later
@@ -113,3 +114,5 @@ module ActionMailbox
end
end
end
+
+ActiveSupport.run_load_hooks :action_mailbox, ActionMailbox::Base
diff --git a/actionmailbox/lib/action_mailbox/engine.rb b/actionmailbox/lib/action_mailbox/engine.rb
index 0400469ff7..d5a07a7dce 100644
--- a/actionmailbox/lib/action_mailbox/engine.rb
+++ b/actionmailbox/lib/action_mailbox/engine.rb
@@ -1,6 +1,11 @@
# frozen_string_literal: true
-require "rails/engine"
+require "rails"
+require "action_controller/railtie"
+require "active_job/railtie"
+require "active_record/railtie"
+require "active_storage/engine"
+
require "action_mailbox"
module ActionMailbox
diff --git a/actionmailbox/lib/action_mailbox/gem_version.rb b/actionmailbox/lib/action_mailbox/gem_version.rb
index 3959de9ce1..1f9c4272b9 100644
--- a/actionmailbox/lib/action_mailbox/gem_version.rb
+++ b/actionmailbox/lib/action_mailbox/gem_version.rb
@@ -10,7 +10,7 @@ module ActionMailbox
MAJOR = 6
MINOR = 0
TINY = 0
- PRE = "alpha"
+ PRE = "beta1"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionmailbox/lib/action_mailbox/postfix_relayer.rb b/actionmailbox/lib/action_mailbox/relayer.rb
index d43c56ed2b..e2890acb60 100644
--- a/actionmailbox/lib/action_mailbox/postfix_relayer.rb
+++ b/actionmailbox/lib/action_mailbox/relayer.rb
@@ -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
diff --git a/actionmailbox/lib/action_mailbox/router/route.rb b/actionmailbox/lib/action_mailbox/router/route.rb
index b681eb7ea8..7e98e83382 100644
--- a/actionmailbox/lib/action_mailbox/router/route.rb
+++ b/actionmailbox/lib/action_mailbox/router/route.rb
@@ -2,7 +2,7 @@
module ActionMailbox
# Encapsulates a route, which can then be matched against an inbound_email and provide a lookup of the matching
- # mailbox class. See examples for the different route addresses and how to use them in the `ActionMailbox::Base`
+ # mailbox class. See examples for the different route addresses and how to use them in the +ActionMailbox::Base+
# documentation.
class Router::Route
attr_reader :address, :mailbox_name
diff --git a/actionmailbox/lib/action_mailbox/routing.rb b/actionmailbox/lib/action_mailbox/routing.rb
index 1ea96c8a9d..58462a44c6 100644
--- a/actionmailbox/lib/action_mailbox/routing.rb
+++ b/actionmailbox/lib/action_mailbox/routing.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module ActionMailbox
- # See `ActionMailbox::Base` for how to specify routing.
+ # See +ActionMailbox::Base+ for how to specify routing.
module Routing
extend ActiveSupport::Concern
diff --git a/actionmailbox/lib/action_mailbox/test_case.rb b/actionmailbox/lib/action_mailbox/test_case.rb
index a501e8a7ca..5e78e428d3 100644
--- a/actionmailbox/lib/action_mailbox/test_case.rb
+++ b/actionmailbox/lib/action_mailbox/test_case.rb
@@ -8,3 +8,5 @@ module ActionMailbox
include ActionMailbox::TestHelper
end
end
+
+ActiveSupport.run_load_hooks :action_mailbox_test_case, ActionMailbox::TestCase
diff --git a/actionmailbox/lib/action_mailbox/test_helper.rb b/actionmailbox/lib/action_mailbox/test_helper.rb
index 02c52fb779..0ec9152844 100644
--- a/actionmailbox/lib/action_mailbox/test_helper.rb
+++ b/actionmailbox/lib/action_mailbox/test_helper.rb
@@ -4,38 +4,38 @@ require "mail"
module ActionMailbox
module TestHelper
- # Create an `InboundEmail` record using an eml fixture in the format of message/rfc822
+ # Create an +InboundEmail+ record using an eml fixture in the format of message/rfc822
# referenced with +fixture_name+ located in +test/fixtures/files/fixture_name+.
def create_inbound_email_from_fixture(fixture_name, status: :processing)
create_inbound_email_from_source file_fixture(fixture_name).read, status: status
end
- # Create an `InboundEmail` by specifying it using `Mail.new` options. Example:
+ # Create an +InboundEmail+ by specifying it using +Mail.new+ options. Example:
#
# create_inbound_email_from_mail(from: "david@loudthinking.com", subject: "Hello!")
def create_inbound_email_from_mail(status: :processing, **mail_options)
create_inbound_email_from_source Mail.new(mail_options).to_s, status: status
end
- # Create an `InboundEmail` using the raw rfc822 `source` as text.
+ # Create an +InboundEmail+ using the raw rfc822 +source+ as text.
def create_inbound_email_from_source(source, status: :processing)
ActionMailbox::InboundEmail.create_and_extract_message_id! source, status: status
end
- # Create an `InboundEmail` from fixture using the same arguments as `create_inbound_email_from_fixture`
+ # Create an +InboundEmail+ from fixture using the same arguments as +create_inbound_email_from_fixture+
# and immediately route it to processing.
def receive_inbound_email_from_fixture(*args)
create_inbound_email_from_fixture(*args).tap(&:route)
end
- # Create an `InboundEmail` from fixture using the same arguments as `create_inbound_email_from_mail`
+ # Create an +InboundEmail+ from fixture using the same arguments as +create_inbound_email_from_mail+
# and immediately route it to processing.
def receive_inbound_email_from_mail(**kwargs)
create_inbound_email_from_mail(**kwargs).tap(&:route)
end
- # Create an `InboundEmail` from fixture using the same arguments as `create_inbound_email_from_source`
+ # Create an +InboundEmail+ from fixture using the same arguments as +create_inbound_email_from_source+
# and immediately route it to processing.
def receive_inbound_email_from_source(**kwargs)
create_inbound_email_from_source(**kwargs).tap(&:route)
diff --git a/actionmailbox/lib/rails/generators/mailbox/templates/application_mailbox.rb.tt b/actionmailbox/lib/rails/generators/mailbox/templates/application_mailbox.rb.tt
index be51eb3639..ac22d03cd2 100644
--- a/actionmailbox/lib/rails/generators/mailbox/templates/application_mailbox.rb.tt
+++ b/actionmailbox/lib/rails/generators/mailbox/templates/application_mailbox.rb.tt
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
class ApplicationMailbox < ActionMailbox::Base
# routing /something/i => :somewhere
end
diff --git a/actionmailbox/lib/rails/generators/mailbox/templates/mailbox.rb.tt b/actionmailbox/lib/rails/generators/mailbox/templates/mailbox.rb.tt
index 56b138e2d9..110b3b9d7e 100644
--- a/actionmailbox/lib/rails/generators/mailbox/templates/mailbox.rb.tt
+++ b/actionmailbox/lib/rails/generators/mailbox/templates/mailbox.rb.tt
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
class <%= class_name %>Mailbox < ApplicationMailbox
def process
end
diff --git a/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt b/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt
index 41749808e3..0b51f29fe4 100644
--- a/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt
+++ b/actionmailbox/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt
@@ -5,7 +5,7 @@ require "test_helper"
class <%= class_name %>MailboxTest < ActionMailbox::TestCase
# test "receive mail" do
# receive_inbound_email_from_mail \
- # to: '"someone" <someone@example.com>,
+ # to: '"someone" <someone@example.com>',
# from: '"else" <else@example.com>',
# subject: "Hello world!",
# body: "Hello?"
diff --git a/actionmailbox/lib/tasks/ingress.rake b/actionmailbox/lib/tasks/ingress.rake
index f775bbdfd7..43b613ea12 100644
--- a/actionmailbox/lib/tasks/ingress.rake
+++ b/actionmailbox/lib/tasks/ingress.rake
@@ -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