actionmailbox 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +159 -0
- data/LICENSE +21 -0
- data/README.md +278 -0
- data/Rakefile +27 -0
- data/actionmailbox.gemspec +27 -0
- data/app/controllers/action_mailbox/base_controller.rb +43 -0
- data/app/controllers/action_mailbox/ingresses/amazon/inbound_emails_controller.rb +50 -0
- data/app/controllers/action_mailbox/ingresses/mailgun/inbound_emails_controller.rb +99 -0
- data/app/controllers/action_mailbox/ingresses/mandrill/inbound_emails_controller.rb +78 -0
- data/app/controllers/action_mailbox/ingresses/postfix/inbound_emails_controller.rb +55 -0
- data/app/controllers/action_mailbox/ingresses/sendgrid/inbound_emails_controller.rb +50 -0
- data/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb +27 -0
- data/app/controllers/rails/conductor/action_mailbox/reroutes_controller.rb +15 -0
- data/app/controllers/rails/conductor/base_controller.rb +10 -0
- data/app/jobs/action_mailbox/incineration_job.rb +18 -0
- data/app/jobs/action_mailbox/routing_job.rb +9 -0
- data/app/models/action_mailbox/inbound_email.rb +43 -0
- data/app/models/action_mailbox/inbound_email/incineratable.rb +18 -0
- data/app/models/action_mailbox/inbound_email/incineratable/incineration.rb +22 -0
- data/app/models/action_mailbox/inbound_email/message_id.rb +36 -0
- data/app/models/action_mailbox/inbound_email/routable.rb +22 -0
- data/app/views/layouts/rails/conductor.html.erb +7 -0
- data/app/views/rails/conductor/action_mailbox/inbound_emails/index.html.erb +15 -0
- data/app/views/rails/conductor/action_mailbox/inbound_emails/new.html.erb +42 -0
- data/app/views/rails/conductor/action_mailbox/inbound_emails/show.html.erb +15 -0
- data/bin/test +5 -0
- data/config/routes.rb +19 -0
- data/db/migrate/20180917164000_create_action_mailbox_tables.rb +11 -0
- data/lib/action_mailbox.rb +15 -0
- data/lib/action_mailbox/base.rb +111 -0
- data/lib/action_mailbox/callbacks.rb +32 -0
- data/lib/action_mailbox/engine.rb +34 -0
- data/lib/action_mailbox/mail_ext.rb +4 -0
- data/lib/action_mailbox/mail_ext/address_equality.rb +5 -0
- data/lib/action_mailbox/mail_ext/address_wrapping.rb +5 -0
- data/lib/action_mailbox/mail_ext/addresses.rb +25 -0
- data/lib/action_mailbox/mail_ext/from_source.rb +5 -0
- data/lib/action_mailbox/mail_ext/recipients.rb +5 -0
- data/lib/action_mailbox/postfix_relayer.rb +67 -0
- data/lib/action_mailbox/router.rb +38 -0
- data/lib/action_mailbox/router/route.rb +38 -0
- data/lib/action_mailbox/routing.rb +20 -0
- data/lib/action_mailbox/test_case.rb +8 -0
- data/lib/action_mailbox/test_helper.rb +42 -0
- data/lib/action_mailbox/version.rb +3 -0
- data/lib/tasks/ingress.rake +24 -0
- data/lib/tasks/install.rake +20 -0
- data/lib/templates/installer.rb +4 -0
- data/lib/templates/mailboxes/application_mailbox.rb +3 -0
- data/test/controllers/ingresses/amazon/inbound_emails_controller_test.rb +20 -0
- data/test/controllers/ingresses/mailgun/inbound_emails_controller_test.rb +89 -0
- data/test/controllers/ingresses/mandrill/inbound_emails_controller_test.rb +58 -0
- data/test/controllers/ingresses/postfix/inbound_emails_controller_test.rb +54 -0
- data/test/controllers/ingresses/sendgrid/inbound_emails_controller_test.rb +44 -0
- data/test/dummy/.babelrc +18 -0
- data/test/dummy/.gitignore +3 -0
- data/test/dummy/.postcssrc.yml +3 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/assets/stylesheets/scaffold.css +80 -0
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/javascript/packs/application.js +0 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailboxes/application_mailbox.rb +2 -0
- data/test/dummy/app/mailboxes/messages_mailbox.rb +4 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +36 -0
- data/test/dummy/bin/update +31 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/config/application.rb +19 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +63 -0
- data/test/dummy/config/environments/production.rb +96 -0
- data/test/dummy/config/environments/test.rb +46 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/assets.rb +14 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/content_security_policy.rb +22 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +34 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config/storage.yml +35 -0
- data/test/dummy/config/webpack/development.js +3 -0
- data/test/dummy/config/webpack/environment.js +3 -0
- data/test/dummy/config/webpack/production.js +3 -0
- data/test/dummy/config/webpack/test.js +3 -0
- data/test/dummy/config/webpacker.yml +65 -0
- data/test/dummy/db/migrate/20180208205311_create_action_mailroom_tables.rb +11 -0
- data/test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb +26 -0
- data/test/dummy/db/schema.rb +43 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/package.json +11 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/storage/.keep +0 -0
- data/test/dummy/yarn.lock +6071 -0
- data/test/fixtures/files/welcome.eml +631 -0
- data/test/jobs/incineration_job_test.rb +17 -0
- data/test/test_helper.rb +54 -0
- data/test/unit/inbound_email/incineration_test.rb +45 -0
- data/test/unit/inbound_email/message_id_test.rb +13 -0
- data/test/unit/inbound_email_test.rb +13 -0
- data/test/unit/mail_ext/address_equality_test.rb +9 -0
- data/test/unit/mail_ext/address_wrapping_test.rb +11 -0
- data/test/unit/mail_ext/recipients_test.rb +33 -0
- data/test/unit/mailbox/bouncing_test.rb +29 -0
- data/test/unit/mailbox/callbacks_test.rb +75 -0
- data/test/unit/mailbox/routing_test.rb +30 -0
- data/test/unit/mailbox/state_test.rb +49 -0
- data/test/unit/postfix_relayer_test.rb +90 -0
- data/test/unit/router_test.rb +137 -0
- metadata +355 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class ActionMailbox::IncinerationJobTest < ActiveJob::TestCase
|
|
6
|
+
setup { @inbound_email = receive_inbound_email_from_fixture("welcome.eml") }
|
|
7
|
+
|
|
8
|
+
test "ignoring a missing inbound email" do
|
|
9
|
+
@inbound_email.destroy!
|
|
10
|
+
|
|
11
|
+
perform_enqueued_jobs do
|
|
12
|
+
assert_nothing_raised do
|
|
13
|
+
ActionMailbox::IncinerationJob.perform_later @inbound_email
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
|
2
|
+
ENV["RAILS_INBOUND_EMAIL_PASSWORD"] = "tbsy84uSV1Kt3ZJZELY2TmShPRs91E3yL4tzf96297vBCkDWgL"
|
|
3
|
+
|
|
4
|
+
require_relative "../test/dummy/config/environment"
|
|
5
|
+
ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
|
|
6
|
+
require "rails/test_help"
|
|
7
|
+
|
|
8
|
+
require "byebug"
|
|
9
|
+
require "webmock/minitest"
|
|
10
|
+
|
|
11
|
+
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
|
12
|
+
|
|
13
|
+
require "rails/test_unit/reporter"
|
|
14
|
+
Rails::TestUnitReporter.executable = 'bin/test'
|
|
15
|
+
|
|
16
|
+
if ActiveSupport::TestCase.respond_to?(:fixture_path=)
|
|
17
|
+
ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__)
|
|
18
|
+
ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
|
|
19
|
+
ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files"
|
|
20
|
+
ActiveSupport::TestCase.fixtures :all
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require "action_mailbox/test_helper"
|
|
24
|
+
|
|
25
|
+
class ActiveSupport::TestCase
|
|
26
|
+
include ActionMailbox::TestHelper, ActiveJob::TestHelper
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class ActionDispatch::IntegrationTest
|
|
30
|
+
private
|
|
31
|
+
def credentials
|
|
32
|
+
ActionController::HttpAuthentication::Basic.encode_credentials "actionmailbox", ENV["RAILS_INBOUND_EMAIL_PASSWORD"]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def switch_password_to(new_password)
|
|
36
|
+
previous_password, ENV["RAILS_INBOUND_EMAIL_PASSWORD"] = ENV["RAILS_INBOUND_EMAIL_PASSWORD"], new_password
|
|
37
|
+
yield
|
|
38
|
+
ensure
|
|
39
|
+
ENV["RAILS_INBOUND_EMAIL_PASSWORD"] = previous_password
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if ARGV.include?("-v")
|
|
44
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
45
|
+
ActiveJob::Base.logger = Logger.new(STDOUT)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class BounceMailer < ActionMailer::Base
|
|
49
|
+
def bounce(to:)
|
|
50
|
+
mail from: "receiver@example.com", to: to, subject: "Your email was not delivered" do |format|
|
|
51
|
+
format.html { render plain: "Sorry!" }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
class ActionMailbox::InboundEmail::IncinerationTest < ActiveSupport::TestCase
|
|
4
|
+
test "incinerating 30 days after delivery" do
|
|
5
|
+
freeze_time
|
|
6
|
+
|
|
7
|
+
assert_enqueued_with job: ActionMailbox::IncinerationJob, at: 30.days.from_now do
|
|
8
|
+
create_inbound_email_from_fixture("welcome.eml").delivered!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
travel 30.days
|
|
12
|
+
|
|
13
|
+
assert_difference -> { ActionMailbox::InboundEmail.count }, -1 do
|
|
14
|
+
perform_enqueued_jobs only: ActionMailbox::IncinerationJob
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
test "incinerating 30 days after bounce" do
|
|
19
|
+
freeze_time
|
|
20
|
+
|
|
21
|
+
assert_enqueued_with job: ActionMailbox::IncinerationJob, at: 30.days.from_now do
|
|
22
|
+
create_inbound_email_from_fixture("welcome.eml").bounced!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
travel 30.days
|
|
26
|
+
|
|
27
|
+
assert_difference -> { ActionMailbox::InboundEmail.count }, -1 do
|
|
28
|
+
perform_enqueued_jobs only: ActionMailbox::IncinerationJob
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
test "incinerating 30 days after failure" do
|
|
33
|
+
freeze_time
|
|
34
|
+
|
|
35
|
+
assert_enqueued_with job: ActionMailbox::IncinerationJob, at: 30.days.from_now do
|
|
36
|
+
create_inbound_email_from_fixture("welcome.eml").failed!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
travel 30.days
|
|
40
|
+
|
|
41
|
+
assert_difference -> { ActionMailbox::InboundEmail.count }, -1 do
|
|
42
|
+
perform_enqueued_jobs only: ActionMailbox::IncinerationJob
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
class ActionMailbox::InboundEmail::MessageIdTest < ActiveSupport::TestCase
|
|
4
|
+
test "message id is extracted from raw email" do
|
|
5
|
+
inbound_email = create_inbound_email_from_fixture("welcome.eml")
|
|
6
|
+
assert_equal "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com", inbound_email.message_id
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
test "message id is generated if its missing" do
|
|
10
|
+
inbound_email = create_inbound_email_from_source "Date: Fri, 28 Sep 2018 11:08:55 -0700\r\nTo: a@example.com\r\nMime-Version: 1.0\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: 7bit\r\n\r\nHello!"
|
|
11
|
+
assert_not_nil inbound_email.message_id
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require_relative '../test_helper'
|
|
2
|
+
|
|
3
|
+
module ActionMailbox
|
|
4
|
+
class InboundEmailTest < ActiveSupport::TestCase
|
|
5
|
+
test "mail provides the parsed source" do
|
|
6
|
+
assert_equal "Discussion: Let's debate these attachments", create_inbound_email_from_fixture("welcome.eml").mail.subject
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
test "source returns the contents of the raw email" do
|
|
10
|
+
assert_equal file_fixture("welcome.eml").read, create_inbound_email_from_fixture("welcome.eml").source
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
module MailExt
|
|
4
|
+
class AddressEqualityTest < ActiveSupport::TestCase
|
|
5
|
+
test "two addresses with the same address are equal" do
|
|
6
|
+
assert_equal Mail::Address.new("david@basecamp.com"), Mail::Address.new("david@basecamp.com")
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
module MailExt
|
|
4
|
+
class AddressWrappingTest < ActiveSupport::TestCase
|
|
5
|
+
test "wrap" do
|
|
6
|
+
needing_wrapping = Mail::Address.wrap("david@basecamp.com")
|
|
7
|
+
wrapping_not_needed = Mail::Address.wrap(Mail::Address.new("david@basecamp.com"))
|
|
8
|
+
assert_equal needing_wrapping.address, wrapping_not_needed.address
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
module MailExt
|
|
4
|
+
class RecipientsTest < ActiveSupport::TestCase
|
|
5
|
+
setup do
|
|
6
|
+
@mail = Mail.new \
|
|
7
|
+
to: "david@basecamp.com",
|
|
8
|
+
cc: "jason@basecamp.com",
|
|
9
|
+
bcc: "andrea@basecamp.com",
|
|
10
|
+
x_original_to: "ryan@basecamp.com"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "recipients include everyone from to, cc, bcc, and x-original-to" do
|
|
14
|
+
assert_equal %w[ david@basecamp.com jason@basecamp.com andrea@basecamp.com ryan@basecamp.com ], @mail.recipients
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "recipients addresses use address objects" do
|
|
18
|
+
assert_equal "basecamp.com", @mail.recipients_addresses.first.domain
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
test "to addresses use address objects" do
|
|
22
|
+
assert_equal "basecamp.com", @mail.to_addresses.first.domain
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
test "cc addresses use address objects" do
|
|
26
|
+
assert_equal "basecamp.com", @mail.cc_addresses.first.domain
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
test "bcc addresses use address objects" do
|
|
30
|
+
assert_equal "basecamp.com", @mail.bcc_addresses.first.domain
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
class BouncingWithReplyMailbox < ActionMailbox::Base
|
|
4
|
+
def process
|
|
5
|
+
bounce_with BounceMailer.bounce(to: mail.from)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class ActionMailbox::Base::BouncingTest < ActiveSupport::TestCase
|
|
10
|
+
include ActionMailer::TestHelper
|
|
11
|
+
|
|
12
|
+
setup do
|
|
13
|
+
@inbound_email = create_inbound_email_from_mail \
|
|
14
|
+
from: "sender@example.com", to: "replies@example.com", subject: "Bounce me"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "bouncing with a reply" do
|
|
18
|
+
perform_enqueued_jobs only: ActionMailer::DeliveryJob do
|
|
19
|
+
BouncingWithReplyMailbox.receive @inbound_email
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
assert @inbound_email.bounced?
|
|
23
|
+
assert_emails 1
|
|
24
|
+
|
|
25
|
+
mail = ActionMailer::Base.deliveries.last
|
|
26
|
+
assert_equal %w[ sender@example.com ], mail.to
|
|
27
|
+
assert_equal "Your email was not delivered", mail.subject
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
class CallbackMailbox < ActionMailbox::Base
|
|
4
|
+
before_processing { $before_processing = "Ran that!" }
|
|
5
|
+
after_processing { $after_processing = "Ran that too!" }
|
|
6
|
+
around_processing ->(r, block) { block.call; $around_processing = "Ran that as well!" }
|
|
7
|
+
|
|
8
|
+
def process
|
|
9
|
+
$processed = mail.subject
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class BouncingCallbackMailbox < ActionMailbox::Base
|
|
14
|
+
before_processing { $before_processing = [ "Pre-bounce" ] }
|
|
15
|
+
|
|
16
|
+
before_processing do
|
|
17
|
+
bounce_with BounceMailer.bounce(to: mail.from)
|
|
18
|
+
$before_processing << "Bounce"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
before_processing { $before_processing << "Post-bounce" }
|
|
22
|
+
|
|
23
|
+
after_processing { $after_processing = true }
|
|
24
|
+
|
|
25
|
+
def process
|
|
26
|
+
$processed = true
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class DiscardingCallbackMailbox < ActionMailbox::Base
|
|
31
|
+
before_processing { $before_processing = [ "Pre-discard" ] }
|
|
32
|
+
|
|
33
|
+
before_processing do
|
|
34
|
+
delivered!
|
|
35
|
+
$before_processing << "Discard"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
before_processing { $before_processing << "Post-discard" }
|
|
39
|
+
|
|
40
|
+
after_processing { $after_processing = true }
|
|
41
|
+
|
|
42
|
+
def process
|
|
43
|
+
$processed = true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class ActionMailbox::Base::CallbacksTest < ActiveSupport::TestCase
|
|
48
|
+
setup do
|
|
49
|
+
$before_processing = $after_processing = $around_processing = $processed = false
|
|
50
|
+
@inbound_email = create_inbound_email_from_fixture("welcome.eml")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
test "all callback types" do
|
|
54
|
+
CallbackMailbox.receive @inbound_email
|
|
55
|
+
assert_equal "Ran that!", $before_processing
|
|
56
|
+
assert_equal "Ran that too!", $after_processing
|
|
57
|
+
assert_equal "Ran that as well!", $around_processing
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
test "bouncing in a callback terminates processing" do
|
|
61
|
+
BouncingCallbackMailbox.receive @inbound_email
|
|
62
|
+
assert @inbound_email.bounced?
|
|
63
|
+
assert_equal [ "Pre-bounce", "Bounce" ], $before_processing
|
|
64
|
+
assert_not $processed
|
|
65
|
+
assert_not $after_processing
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
test "marking the inbound email as delivered in a callback terminates processing" do
|
|
69
|
+
DiscardingCallbackMailbox.receive @inbound_email
|
|
70
|
+
assert @inbound_email.delivered?
|
|
71
|
+
assert_equal [ "Pre-discard", "Discard" ], $before_processing
|
|
72
|
+
assert_not $processed
|
|
73
|
+
assert_not $after_processing
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
class ApplicationMailbox < ActionMailbox::Base
|
|
4
|
+
routing "replies@example.com" => :replies
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class RepliesMailbox < ActionMailbox::Base
|
|
8
|
+
def process
|
|
9
|
+
$processed = mail.subject
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ActionMailbox::Base::RoutingTest < ActiveSupport::TestCase
|
|
14
|
+
setup do
|
|
15
|
+
$processed = false
|
|
16
|
+
@inbound_email = create_inbound_email_from_fixture("welcome.eml")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test "string routing" do
|
|
20
|
+
ApplicationMailbox.route @inbound_email
|
|
21
|
+
assert_equal "Discussion: Let's debate these attachments", $processed
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test "delayed routing" do
|
|
25
|
+
perform_enqueued_jobs only: ActionMailbox::RoutingJob do
|
|
26
|
+
create_inbound_email_from_fixture "welcome.eml", status: :pending
|
|
27
|
+
assert_equal "Discussion: Let's debate these attachments", $processed
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require_relative '../../test_helper'
|
|
2
|
+
|
|
3
|
+
class SuccessfulMailbox < ActionMailbox::Base
|
|
4
|
+
def process
|
|
5
|
+
$processed = mail.subject
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class UnsuccessfulMailbox < ActionMailbox::Base
|
|
10
|
+
rescue_from(RuntimeError) { $processed = :failure }
|
|
11
|
+
|
|
12
|
+
def process
|
|
13
|
+
raise "No way!"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class BouncingMailbox < ActionMailbox::Base
|
|
18
|
+
def process
|
|
19
|
+
$processed = :bounced
|
|
20
|
+
bounced!
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ActionMailbox::Base::StateTest < ActiveSupport::TestCase
|
|
26
|
+
setup do
|
|
27
|
+
$processed = false
|
|
28
|
+
@inbound_email = create_inbound_email_from_mail \
|
|
29
|
+
to: "replies@example.com", subject: "I was processed"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
test "successful mailbox processing leaves inbound email in delivered state" do
|
|
33
|
+
SuccessfulMailbox.receive @inbound_email
|
|
34
|
+
assert @inbound_email.delivered?
|
|
35
|
+
assert_equal "I was processed", $processed
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
test "unsuccessful mailbox processing leaves inbound email in failed state" do
|
|
39
|
+
UnsuccessfulMailbox.receive @inbound_email
|
|
40
|
+
assert @inbound_email.failed?
|
|
41
|
+
assert_equal :failure, $processed
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
test "bounced inbound emails are not delivered" do
|
|
45
|
+
BouncingMailbox.receive @inbound_email
|
|
46
|
+
assert @inbound_email.bounced?
|
|
47
|
+
assert_equal :bounced, $processed
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require_relative '../test_helper'
|
|
2
|
+
|
|
3
|
+
require 'action_mailbox/postfix_relayer'
|
|
4
|
+
|
|
5
|
+
module ActionMailbox
|
|
6
|
+
class PostfixRelayerTest < ActiveSupport::TestCase
|
|
7
|
+
URL = "https://example.com/rails/action_mailbox/postfix/inbound_emails"
|
|
8
|
+
INGRESS_PASSWORD = "secret"
|
|
9
|
+
|
|
10
|
+
setup do
|
|
11
|
+
@relayer = ActionMailbox::PostfixRelayer.new(url: URL, password: INGRESS_PASSWORD)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
test "successfully relaying an email" do
|
|
15
|
+
stub_request(:post, URL).to_return status: 204
|
|
16
|
+
|
|
17
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
18
|
+
assert_equal "2.0.0 Successfully relayed message to Postfix ingress", result.output
|
|
19
|
+
assert result.success?
|
|
20
|
+
assert_not result.failure?
|
|
21
|
+
|
|
22
|
+
assert_requested :post, URL, body: file_fixture("welcome.eml").read,
|
|
23
|
+
basic_auth: [ "actionmailbox", INGRESS_PASSWORD ],
|
|
24
|
+
headers: { "Content-Type" => "message/rfc822", "User-Agent" => /\AAction Mailbox Postfix relayer v\d+\./ }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
test "unsuccessfully relaying with invalid credentials" do
|
|
28
|
+
stub_request(:post, URL).to_return status: 401
|
|
29
|
+
|
|
30
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
31
|
+
assert_equal "4.7.0 Invalid credentials for Postfix ingress", result.output
|
|
32
|
+
assert_not result.success?
|
|
33
|
+
assert result.failure?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
test "unsuccessfully relaying due to an unspecified server error" do
|
|
37
|
+
stub_request(:post, URL).to_return status: 500
|
|
38
|
+
|
|
39
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
40
|
+
assert_equal "4.0.0 HTTP 500", result.output
|
|
41
|
+
assert_not result.success?
|
|
42
|
+
assert result.failure?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
test "unsuccessfully relaying due to a gateway timeout" do
|
|
46
|
+
stub_request(:post, URL).to_return status: 504
|
|
47
|
+
|
|
48
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
49
|
+
assert_equal "4.0.0 HTTP 504", result.output
|
|
50
|
+
assert_not result.success?
|
|
51
|
+
assert result.failure?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
test "unsuccessfully relaying due to ECONNRESET" do
|
|
55
|
+
stub_request(:post, URL).to_raise Errno::ECONNRESET.new
|
|
56
|
+
|
|
57
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
58
|
+
assert_equal "4.4.2 Network error relaying to Postfix ingress: Connection reset by peer", result.output
|
|
59
|
+
assert_not result.success?
|
|
60
|
+
assert result.failure?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test "unsuccessfully relaying due to connection failure" do
|
|
64
|
+
stub_request(:post, URL).to_raise SocketError.new("Failed to open TCP connection to example.com:443")
|
|
65
|
+
|
|
66
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
67
|
+
assert_equal "4.4.2 Network error relaying to Postfix ingress: Failed to open TCP connection to example.com:443", result.output
|
|
68
|
+
assert_not result.success?
|
|
69
|
+
assert result.failure?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
test "unsuccessfully relaying due to client-side timeout" do
|
|
73
|
+
stub_request(:post, URL).to_timeout
|
|
74
|
+
|
|
75
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
76
|
+
assert_equal "4.4.2 Timed out relaying to Postfix ingress", result.output
|
|
77
|
+
assert_not result.success?
|
|
78
|
+
assert result.failure?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
test "unsuccessfully relaying due to an unhandled exception" do
|
|
82
|
+
stub_request(:post, URL).to_raise StandardError.new("Something went wrong")
|
|
83
|
+
|
|
84
|
+
result = @relayer.relay(file_fixture("welcome.eml").read)
|
|
85
|
+
assert_equal "4.0.0 Error relaying to Postfix ingress: Something went wrong", result.output
|
|
86
|
+
assert_not result.success?
|
|
87
|
+
assert result.failure?
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|