diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b6ecf951..ca641157 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,23 +19,30 @@ jobs:
fail-fast: false
matrix:
ruby: [2.7, '3.0', 3.1, 3.2, 3.3, jruby-9.4]
- rails: [7.1, 7.2, main]
+ rails: [7.1, 7.2, '8.0', main]
exclude:
- # Rails 7.2 dropped support for older rubygems
+ # Rails 7.2 is Ruby >= 3.1
- rails: 7.2
ruby: 2.7
- rails: 7.2
ruby: 3.0
+ # Rails 8.0 is Ruby >= 3.2
+ - rails: '8.0'
+ ruby: 2.7
+ - rails: '8.0'
+ ruby: 3.0
+ - rails: '8.0'
+ ruby: 3.1
+ - rails: '8.0'
+ ruby: jruby-9.4
+ # Rails main is Ruby >= 3.2
- rails: main
ruby: 2.7
- rails: main
ruby: 3.0
- rails: main
ruby: 3.1
- # JDBC adapters don't support the latest Rails
- - rails: 7.2
- ruby: jruby-9.4
- rails: main
ruby: jruby-9.4
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41f309c1..ac544085 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,10 @@ Unreleased Changes
* Issue - Add deprecation warning to `Aws::Rails.add_action_mailer_delivery_method` to instead use `ActionMailer::Base.add_delivery_method`. This method will be removed in the next major version.
+* Feature - ActionMailbox SES ingress now lives in the `aws-actionmailbox-ses` gem.
+
+* Issue - The `Aws::Rails::ActionMailbox::RSpec` module has been moved to `Aws::ActionMailbox::SES::RSpec` and will be removed in aws-sdk-rails ~> 5.
+
4.1.0 (2024-09-27)
------------------
diff --git a/Gemfile b/Gemfile
index 3169ba2e..bd8d6d65 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,6 +5,7 @@ source 'https://rubygems.org'
gemspec
gem 'aws-actiondispatch-dynamodb', git: 'https://github.com/aws/aws-actiondispatch-dynamodb-ruby'
+gem 'aws-actionmailbox-ses', git: 'https://github.com/aws/aws-actionmailbox-ses-ruby'
gem 'aws-actionmailer-ses', git: 'https://github.com/aws/aws-actionmailer-ses-ruby'
group :development, :test do
diff --git a/README.md b/README.md
index bbc3c885..014fb701 100644
--- a/README.md
+++ b/README.md
@@ -222,7 +222,30 @@ In your environment configuration, set the delivery method to
config.action_mailer.delivery_method = :ses # or :ses_v2
```
-## Amazon Simple Email Service (SES) as an ActionMailbox Method
+### Using ARNs with SES
+
+This gem uses [\`Aws::SES::Client#send_raw_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SES/Client.html#send_raw_email-instance_method)
+and [\`Aws::SESV2::Client#send_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html#send_email-instance_method)
+to send emails. This operation allows you to specify a cross-account identity
+for the email's Source, From, and Return-Path. To set these ARNs, use any of the
+following headers on your `Mail::Message` object returned by your Mailer class:
+
+* X-SES-SOURCE-ARN
+
+* X-SES-FROM-ARN
+
+* X-SES-RETURN-PATH-ARN
+
+Example:
+
+```
+# in your Rails controller
+message = MyMailer.send_email(options)
+message['X-SES-FROM-ARN'] = 'arn:aws:ses:us-west-2:012345678910:identity/bigchungus@memes.com'
+message.deliver
+```
+
+## Amazon Simple Email Service (SES) as an ActionMailbox Ingress
### Configuration
@@ -307,28 +330,6 @@ You may also pass the following keyword arguments to both helpers:
* `topic`: The _SNS_ topic used for each notification (default: `topic:arn:default`).
* `authentic`: The `Aws::SNS::MessageVerifier` class is stubbed by these helpers; set `authentic` to `true` or `false` to define how it will verify incoming notifications (default: `true`).
-### Using ARNs with SES
-
-This gem uses [\`Aws::SES::Client#send_raw_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SES/Client.html#send_raw_email-instance_method)
-and [\`Aws::SESV2::Client#send_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html#send_email-instance_method)
-to send emails. This operation allows you to specify a cross-account identity
-for the email's Source, From, and Return-Path. To set these ARNs, use any of the
-following headers on your `Mail::Message` object returned by your Mailer class:
-
-* X-SES-SOURCE-ARN
-
-* X-SES-FROM-ARN
-
-* X-SES-RETURN-PATH-ARN
-
-Example:
-
-```
-# in your Rails controller
-message = MyMailer.send_email(options)
-message['X-SES-FROM-ARN'] = 'arn:aws:ses:us-west-2:012345678910:identity/bigchungus@memes.com'
-message.deliver
-```
## Active Support Notifications for AWS SDK calls
diff --git a/Rakefile b/Rakefile
index d1bfc73e..6a411ab5 100644
--- a/Rakefile
+++ b/Rakefile
@@ -4,9 +4,6 @@ require 'rspec/core/rake_task'
require 'rake/testtask'
require 'rubocop/rake_task'
-$REPO_ROOT = File.dirname(__FILE__)
-$VERSION = ENV['VERSION'] || File.read(File.join($REPO_ROOT, 'VERSION')).strip
-
Dir.glob('**/*.rake').each do |task_file|
load task_file
end
@@ -24,14 +21,6 @@ Rake::TestTask.new('test:rails') do |t|
t.warning = false
end
-task :db_migrate do
- Dir.chdir('spec/dummy') do
- version = ENV.delete('VERSION') # ActiveRecord uses this
- `RAILS_ENV=test rake -I ../../lib db:migrate`
- ENV['VERSION'] = version
- end
-end
-
-task test: [:db_migrate, :spec, 'test:rails']
+task test: [:spec, 'test:rails']
task default: :test
task 'release:test' => :test
diff --git a/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb b/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb
deleted file mode 100644
index 83af84a6..00000000
--- a/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-require 'aws/rails/action_mailbox/sns_notification'
-
-module ActionMailbox
- module Ingresses
- module Ses
- # Ingests inbound emails from Amazon SES/SNS and confirms subscriptions.
- #
- # Subscription requests must provide the following parameters in a JSON body:
- # - +Message+: Notification content
- # - +MessagId+: Notification unique identifier
- # - +Timestamp+: iso8601 timestamp
- # - +TopicArn+: Topic identifier
- # - +Type+: Type of event ("Subscription")
- #
- # Inbound email events must provide the following parameters in a JSON body:
- # - +Message+: Notification content
- # - +MessagId+: Notification unique identifier
- # - +Timestamp+: iso8601 timestamp
- # - +SubscribeURL+: Topic identifier
- # - +TopicArn+: Topic identifier
- # - +Type+: Type of event ("SubscriptionConfirmation")
- #
- # All requests are authenticated by validating the provided AWS signature.
- #
- # Returns:
- #
- # - 204 No Content if a request is successfully processed
- # - 401 Unauthorized if a request does not contain a valid signature
- # - 404 Not Found if the Amazon ingress has not been configured
- # - 422 Unprocessable Entity if a request provides invalid parameters
- class InboundEmailsController < ActionMailbox::BaseController
- before_action :verify_authenticity, :validate_topic, :confirm_subscription
-
- def create
- head :bad_request unless notification.message_content.present?
-
- ActionMailbox::InboundEmail.create_and_extract_message_id!(notification.message_content)
- head :no_content
- end
-
- private
-
- def verify_authenticity
- head :bad_request unless notification.present?
- head :unauthorized unless notification.verified?
- end
-
- def confirm_subscription
- return unless notification.type == 'SubscriptionConfirmation'
- return head :ok if notification.subscription_confirmed?
-
- Rails.logger.error('SNS subscription confirmation request rejected.')
- head :unprocessable_entity
- end
-
- def validate_topic
- return if valid_topic == notification.topic
-
- Rails.logger.warn("Ignoring unknown topic: #{topic}")
- head :unauthorized
- end
-
- def notification
- @notification ||= Aws::Rails::ActionMailbox::SnsNotification.new(request.raw_post)
- end
-
- def topic
- @topic ||= notification.topic
- end
-
- def valid_topic
- ::Rails.configuration.action_mailbox.ses.subscribed_topic
- end
- end
- end
- end
-end
diff --git a/aws-sdk-rails.gemspec b/aws-sdk-rails.gemspec
index 589732fc..18c56a3e 100644
--- a/aws-sdk-rails.gemspec
+++ b/aws-sdk-rails.gemspec
@@ -11,20 +11,18 @@ Gem::Specification.new do |spec|
spec.description = 'Integrates the AWS SDK for Ruby with Ruby on Rails'
spec.homepage = 'https://github.com/aws/aws-sdk-rails'
spec.license = 'Apache-2.0'
- spec.files = Dir['LICENSE.txt', 'CHANGELOG.md', 'VERSION', 'lib/**/*', 'bin/*', 'app/**/*', 'config/*']
+ spec.files = Dir['LICENSE.txt', 'CHANGELOG.md', 'VERSION', 'lib/**/*', 'bin/*']
spec.executables = ['aws_sqs_active_job']
# These will be removed in aws-sdk-rails ~> 5
spec.add_dependency('aws-actiondispatch-dynamodb', '~> 0')
+ spec.add_dependency('aws-actionmailbox-ses', '~> 0')
spec.add_dependency('aws-actionmailer-ses', '~> 0')
spec.add_dependency('aws-record', '~> 2') # for Aws::Record integration
# Require these versions for user_agent_framework configs
- spec.add_dependency('aws-sdk-s3', '~> 1', '>= 1.123.0')
- spec.add_dependency('aws-sdk-sns', '~> 1', '>= 1.61.0') # for ActionMailbox
spec.add_dependency('aws-sdk-sqs', '~> 1', '>= 1.56.0') # for ActiveJob
- spec.add_dependency('actionmailbox', '>= 7.1.0') # for SES ActionMailbox
spec.add_dependency('concurrent-ruby', '~> 1.3', '>= 1.3.1') # Utilities for concurrent processing
spec.add_dependency('railties', '>= 7.1.0') # Minimum supported Rails version
diff --git a/config/routes.rb b/config/routes.rb
deleted file mode 100644
index 2a46e464..00000000
--- a/config/routes.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-Rails.application.routes.draw do
- scope '/rails/action_mailbox', module: 'action_mailbox/ingresses' do
- post '/ses/inbound_emails' => 'ses/inbound_emails#create',
- as: :rails_ses_inbound_emails
- end
-end
diff --git a/gemfiles/rails-7.1.gemfile b/gemfiles/rails-7.1.gemfile
index 337c3aae..babb65fd 100644
--- a/gemfiles/rails-7.1.gemfile
+++ b/gemfiles/rails-7.1.gemfile
@@ -3,19 +3,3 @@
eval_gemfile '../Gemfile'
gem 'rails', '~> 7.1.0'
-
-group :test do
- # JDBC versions track Rails versions
- gem 'activerecord-jdbc-adapter', '~> 71.0',
- platform: :jruby,
- # this is not published for some reason
- git: 'https://github.com/jruby/activerecord-jdbc-adapter',
- glob: 'activerecord-jdbc-adapter.gemspec'
- gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0',
- platform: :jruby,
- # this is not published for some reason
- git: 'https://github.com/jruby/activerecord-jdbc-adapter',
- glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec'
- # last supported version of sqlite3 for minimum ruby
- gem 'sqlite3', '~> 1.6.0', platform: :ruby
-end
diff --git a/gemfiles/rails-7.2.gemfile b/gemfiles/rails-7.2.gemfile
index fe96d354..6866a47a 100644
--- a/gemfiles/rails-7.2.gemfile
+++ b/gemfiles/rails-7.2.gemfile
@@ -3,19 +3,3 @@
eval_gemfile '../Gemfile'
gem 'rails', '~> 7.2.0'
-
-group :test do
- # JDBC versions track Rails versions
- gem 'activerecord-jdbc-adapter', '~> 71.0',
- platform: :jruby,
- # this is not published for some reason
- git: 'https://github.com/jruby/activerecord-jdbc-adapter',
- glob: 'activerecord-jdbc-adapter.gemspec'
- gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0',
- platform: :jruby,
- # this is not published for some reason
- git: 'https://github.com/jruby/activerecord-jdbc-adapter',
- glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec'
- # last supported version of sqlite3 for minimum ruby
- gem 'sqlite3', '~> 1.6.0', platform: :ruby
-end
diff --git a/gemfiles/rails-8.0.gemfile b/gemfiles/rails-8.0.gemfile
new file mode 100644
index 00000000..cd3dbac3
--- /dev/null
+++ b/gemfiles/rails-8.0.gemfile
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+eval_gemfile '../Gemfile'
+
+gem 'rails', '~> 8.0.0'
diff --git a/gemfiles/rails-main.gemfile b/gemfiles/rails-main.gemfile
index cd228adf..80b01d94 100644
--- a/gemfiles/rails-main.gemfile
+++ b/gemfiles/rails-main.gemfile
@@ -3,18 +3,3 @@
eval_gemfile '../Gemfile'
gem 'rails', github: 'rails/rails'
-
-group :test do
- # JDBC versions track Rails versions
- gem 'activerecord-jdbc-adapter', '~> 71.0',
- platform: :jruby,
- # this is not published for some reason
- git: 'https://github.com/jruby/activerecord-jdbc-adapter',
- glob: 'activerecord-jdbc-adapter.gemspec'
- gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0',
- platform: :jruby,
- # this is not published for some reason
- git: 'https://github.com/jruby/activerecord-jdbc-adapter',
- glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec'
- gem 'sqlite3', platform: :ruby
-end
diff --git a/lib/aws-sdk-rails.rb b/lib/aws-sdk-rails.rb
index 11f16883..05ce309f 100644
--- a/lib/aws-sdk-rails.rb
+++ b/lib/aws-sdk-rails.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
require_relative 'aws/rails/railtie'
-require_relative 'aws/rails/action_mailbox/engine'
require_relative 'aws/rails/notifications'
require_relative 'aws/rails/sqs_active_job'
require_relative 'aws/rails/middleware/ebs_sqs_active_job_middleware'
# remove this in aws-sdk-rails 5
require 'aws-actiondispatch-dynamodb'
+require 'aws-actionmailbox-ses' if defined?(ActionMailbox::Engine)
require 'aws-actionmailer-ses'
module Aws
diff --git a/lib/aws/rails/action_mailbox/engine.rb b/lib/aws/rails/action_mailbox/engine.rb
deleted file mode 100644
index e682d904..00000000
--- a/lib/aws/rails/action_mailbox/engine.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-if defined?(ActionMailbox::Engine)
- module Aws
- module Rails
- module ActionMailbox
- # @api private
- class Engine < ::Rails::Engine
- config.action_mailbox.ses = ActiveSupport::OrderedOptions.new
- config.action_mailbox.ses.s3_client_options ||= {}
-
- initializer 'aws-sdk-rails.mount_engine' do |app|
- app.routes.append do
- mount Engine => '/'
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/aws/rails/action_mailbox/rspec.rb b/lib/aws/rails/action_mailbox/rspec.rb
index d03b2d6e..51d33680 100644
--- a/lib/aws/rails/action_mailbox/rspec.rb
+++ b/lib/aws/rails/action_mailbox/rspec.rb
@@ -1,69 +1,9 @@
# frozen_string_literal: true
-require 'aws/rails/action_mailbox/rspec/email'
-require 'aws/rails/action_mailbox/rspec/subscription_confirmation'
-require 'aws-sdk-sns'
-require 'aws/rails/action_mailbox/sns_message_verifier'
+# This can be deleted in aws-sdk-rails ~> 5
-module Aws
- module Rails
- module ActionMailbox
- # Include the `Aws::Rails::ActionMailbox::RSpec` extension in your tests, like so:
- # require 'aws/rails/action_mailbox/rspec'
- # RSpec.configure do |config|
- # config.include Aws::Rails::ActionMailbox::RSpec
- # end
- # Then, in a request spec, use like so:
- # RSpec.describe 'amazon emails', type: :request do
- # it 'delivers a subscription notification' do
- # action_mailbox_ses_deliver_subscription_confirmation
- # expect(response).to have_http_status :ok
- # end
+require 'aws/action_mailbox/ses/rspec'
+Aws::Rails::ActionMailbox::Rspec = Aws::ActionMailbox::SES::Rspec
- # it 'delivers an email notification' do
- # action_mailbox_ses_deliver_email(mail: Mail.new(to: 'user@example.com'))
- # expect(ActionMailbox::InboundEmail.last.mail.recipients).to eql ['user@example.com']
- # end
- # end
- module RSpec
- def action_mailbox_ses_deliver_subscription_confirmation(options = {})
- subscription_confirmation = SubscriptionConfirmation.new(**options)
- stub_aws_sns_message_verifier(subscription_confirmation)
- stub_aws_sns_subscription_request
-
- post subscription_confirmation.url,
- params: subscription_confirmation.params,
- headers: subscription_confirmation.headers,
- as: :json
- end
-
- def action_mailbox_ses_deliver_email(options = {})
- email = Email.new(**options)
- stub_aws_sns_message_verifier(email)
-
- post email.url,
- params: email.params,
- headers: email.headers,
- as: :json
- end
-
- private
-
- def message_verifier(subscription_confirmation)
- instance_double(Aws::SNS::MessageVerifier, authentic?: subscription_confirmation.authentic?)
- end
-
- def stub_aws_sns_message_verifier(notification)
- allow(Aws::Rails::ActionMailbox::SnsMessageVerifier).to receive(:verifier) { message_verifier(notification) }
- end
-
- def stub_aws_sns_subscription_request
- allow(Net::HTTP).to receive(:get_response).and_call_original
- allow(Net::HTTP)
- .to receive(:get_response)
- .with(URI('http://example.com/subscribe')) { double(code: '200') }
- end
- end
- end
- end
-end
+Kernel.warn('Aws::Rails::ActionMailbox::Rspec is deprecated in aws-sdk-rails ~> 5. Use Aws::ActionMailbox::SES::Rspec instead.')
+Kernel.warn('Please require "aws/action_mailbox/ses/rspec" instead of "aws/rails/action_mailbox/rspec"')
diff --git a/lib/aws/rails/action_mailbox/rspec/email.rb b/lib/aws/rails/action_mailbox/rspec/email.rb
deleted file mode 100644
index 9ca4d8c5..00000000
--- a/lib/aws/rails/action_mailbox/rspec/email.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-module Aws
- module Rails
- module ActionMailbox
- module RSpec
- # @api private
- class Email
- def initialize(authentic: true, topic: 'topic:arn:default', mail: default_mail, message_params: {})
- @authentic = authentic
- @topic = topic
- @mail = mail
- @message_params = message_params
- end
-
- def headers
- { 'content-type' => 'application/json' }
- end
-
- def url
- '/rails/action_mailbox/ses/inbound_emails'
- end
-
- def params
- {
- 'Type' => 'Notification',
- 'TopicArn' => @topic,
- 'Message' => message_json
- }
- end
-
- def message_json
- {
- 'notificationType' => 'Received',
- 'content' => @mail.encoded
- }.merge(@message_params).to_json
- end
-
- def authentic?
- @authentic
- end
-
- def default_mail
- Mail.new
- end
- end
- end
- end
- end
-end
diff --git a/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb b/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb
deleted file mode 100644
index 52023dbc..00000000
--- a/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module Aws
- module Rails
- module ActionMailbox
- module RSpec
- # @api private
- class SubscriptionConfirmation
- def initialize(authentic: true, topic: 'topic:arn:default')
- @authentic = authentic
- @topic = topic
- end
-
- def url
- '/rails/action_mailbox/ses/inbound_emails'
- end
-
- def headers
- { 'content-type' => 'application/json' }
- end
-
- def params
- {
- 'Type' => 'SubscriptionConfirmation',
- 'TopicArn' => @topic,
- 'SubscribeURL' => 'http://example.com/subscribe'
- }
- end
-
- def authentic?
- @authentic
- end
- end
- end
- end
- end
-end
diff --git a/lib/aws/rails/action_mailbox/s3_client.rb b/lib/aws/rails/action_mailbox/s3_client.rb
deleted file mode 100644
index fa996c90..00000000
--- a/lib/aws/rails/action_mailbox/s3_client.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-require 'aws-sdk-s3'
-
-module Aws
- module Rails
- module ActionMailbox
- # @api private
- class S3Client
- class << self
- def client
- @client ||= build_client
- end
-
- private
-
- def build_client
- client = Aws::S3::Client.new(
- **::Rails.configuration.action_mailbox.ses.s3_client_options
- )
- client.config.user_agent_frameworks << 'aws-sdk-rails'
- client
- end
- end
- end
- end
- end
-end
diff --git a/lib/aws/rails/action_mailbox/sns_message_verifier.rb b/lib/aws/rails/action_mailbox/sns_message_verifier.rb
deleted file mode 100644
index 62560de8..00000000
--- a/lib/aws/rails/action_mailbox/sns_message_verifier.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-require 'aws-sdk-sns'
-
-module Aws
- module Rails
- module ActionMailbox
- # @api private
- class SnsMessageVerifier
- class << self
- def verifier
- @verifier ||= Aws::SNS::MessageVerifier.new
- end
- end
- end
- end
- end
-end
diff --git a/lib/aws/rails/action_mailbox/sns_notification.rb b/lib/aws/rails/action_mailbox/sns_notification.rb
deleted file mode 100644
index 18d97fb2..00000000
--- a/lib/aws/rails/action_mailbox/sns_notification.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-# frozen_string_literal: true
-
-require 'aws-sdk-sns'
-require 'aws/rails/action_mailbox/s3_client'
-require 'aws/rails/action_mailbox/sns_message_verifier'
-
-module Aws
- module Rails
- module ActionMailbox
- # @api private
- class SnsNotification
- class MessageContentError < StandardError; end
-
- def initialize(request_body)
- @request_body = request_body
- end
-
- def subscription_confirmed?
- (200..299).cover?(confirmation_response.code.to_i)
- end
-
- def verified?
- SnsMessageVerifier.verifier.authentic?(@request_body)
- end
-
- def topic
- notification.fetch(:TopicArn)
- end
-
- def type
- notification.fetch(:Type)
- end
-
- def message_content
- raise MessageContentError, 'Incoming emails must have notificationType `Received`' unless receipt?
-
- if content_in_s3?
- s3_content
- else
- return message[:content] unless destination
-
- "X-Original-To: #{destination}\n#{message[:content]}"
- end
- end
-
- private
-
- def notification
- @notification ||= JSON.parse(@request_body, symbolize_names: true)
- rescue JSON::ParserError => e
- Rails.logger.warn("Unable to parse SNS notification: #{e}")
- nil
- end
-
- def s3_content
- S3Client
- .client
- .get_object(key: key, bucket: bucket)
- .body
- .string
- end
-
- def message
- @message ||= JSON.parse(notification[:Message], symbolize_names: true)
- end
-
- def destination
- message.dig(:mail, :destination)&.first
- end
-
- def action
- return unless message[:receipt]
-
- message.fetch(:receipt).fetch(:action)
- end
-
- def bucket
- action.fetch(:bucketName)
- end
-
- def key
- action.fetch(:objectKey)
- end
-
- def content_in_s3?
- action&.fetch(:type) == 'S3'
- end
-
- def receipt?
- message.fetch(:notificationType) == 'Received'
- end
-
- def confirmation_response
- @confirmation_response ||= Net::HTTP.get_response(URI(notification[:SubscribeURL]))
- end
- end
- end
- end
-end
diff --git a/sample-app/Gemfile b/sample-app/Gemfile
index f7a52193..d11b9191 100644
--- a/sample-app/Gemfile
+++ b/sample-app/Gemfile
@@ -2,8 +2,9 @@ source "https://rubygems.org"
# Our gems
gem 'aws-sdk-rails', path: '../'
-gem 'aws-sessionstore-dynamodb' #, path: '../../aws-sessionstore-dynamodb-ruby'
-gem 'aws-actionmailer-ses', git: 'https://github.com/aws/aws-actionmailer-ses-ruby', branch: 'init'
+gem 'aws-actiondispatch-dynamodb', git: 'https://github.com/aws/aws-actiondispatch-dynamodb-ruby'
+gem 'aws-actionmailbox-ses', git: 'https://github.com/aws/aws-actionmailbox-ses-ruby', branch: 'init'
+gem 'aws-actionmailer-ses', git: 'https://github.com/aws/aws-actionmailer-ses-ruby'
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
gem 'bcrypt'
diff --git a/sample-app/README.md b/sample-app/README.md
index c7ab89b1..c22f722e 100644
--- a/sample-app/README.md
+++ b/sample-app/README.md
@@ -114,3 +114,64 @@ Start the service with `ACTION_MAILER_EMAIL= bundle exec rails serve
> **Important**: The email address in SES must be verified.
Visit `http://127.0.0.1:3000/send_ses_email` or `http://127.0.0.1:3000/send_ses_v2_email` and check your email.
+
+## Action Mailbox
+
+### Setup
+
+Following [this guide](https://guides.rubyonrails.org/action_mailbox_basics.html), ActionMailbox was setup with `bundle exec bin/rails action_mailbox:install`.
+
+The database was migrated with: `bundle exec rails db:migrate`.
+
+The ingress and ActiveStorage was configured in `config/environments/development.rb` with:
+
+```ruby
+config.active_storage.service = :local
+config.action_mailbox.ingress = :ses
+```
+
+A default route was added to `app/mailboxes/application_mailbox.rb`.
+
+The test mailbox was created with `bundle exec rails generate mailbox test`.
+
+### Testing
+
+This feature can't fully be tested end to end unless the rails application is hosted on a domain. The SNS topic would have to notify a route such as `https://example.com/rails/action_mailbox/ses/inbound_emails`.
+
+Future work could deploy this sample-app behind a domain to fully test it.
+
+Start the service with `bundle exec rails server` and visit `http://127.0.0.1:3000/rails/conductor/action_mailbox/inbound_emails`.
+
+Click "New inbound email by source".
+
+Use the following message (other messages can be created and signed in aws-actionmailbox-ses):
+
+```
+Return-Path:
+Received: from example.com (example.com [127.0.0.1])
+ by inbound-smtp.us-east-1.amazonaws.com with SMTP id 17at0jiq08p0449huhf16qsmdi6sa1ltm069t801
+ for test@test.example.com;
+ Wed, 02 Sep 2020 01:30:50 +0000 (UTC)
+X-SES-Spam-Verdict: PASS
+X-SES-Virus-Verdict: PASS
+X-SES-RECEIPT: AEFBQUFBQUFBQUFHMWlxem9Gb1ZOemNkamlTeFlYdlZUSmUwVVZhYndjK213dHFIM0dVRTYwUlk1UlpBQVVVTXhQRUd1MTN6YTFJalp0TFdMZjhOOUZGSlJCYkxEV2craXhpOG02d2xDc2FtY2dNdVMvRE9QWWpNVkxBWVZzMyt5MHBTUXV5KzM5aDY1Vng5UnZsZTdTK2dGVDF5RVc1QndOd0xvbndNRlR3TDZjd2cxT2c2UVFQbVN2andMS09VM2R5elFrTGk3RnF0WXI3WDZ1alhkUzJxdzhzU1dwT3FPZEFsU0VNc3RpTWM0QStFZDB5RFd5SnpRelBJWnJjelZPRytudEVpNTc5dVZRUXMra2lrby9wOExhR3JqTi9xNkZnNHREN3BmSmVYS25Jeis2NDRyaEE9PQ==
+X-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=WGBoUguIq9047YXpCaubVCtm/ISR3JEVkvm/yAfL2MrAryQcYsTdUM6zzStPyvOm0QsonOKsWJ0O2YyuQDX1dvBmggdeUqZq08laD+Xuy1L6ODm0O/EQE9wDitj0KqXxOgMr3oM7tpcTTGLcCgXERFZbmI+1ACeeA7fbylMasIM=; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1599010250; v=1; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;
+From: "Smith, Bob E"
+To: "test@test.example.com"
+
+Subject: Test 500
+Thread-Topic: Test 500
+Thread-Index: AQHWgMisvDz2gn/lKEK/giPayBxk7g==
+Date: Wed, 2 Sep 2020 01:30:43 +0000
+Message-ID: <1344C740-07D3-476E-BEE7-6EB162294DF6@example.com>
+Accept-Language: en-US
+Content-Language: en-US
+Content-Type: text/plain; charset="us-ascii"
+Content-ID:
+Content-Transfer-Encoding: quoted-printable
+MIME-Version: 1.0
+
+Aaaron
+```
+
+You should see the message say delivered and not bounced.
\ No newline at end of file
diff --git a/spec/dummy/app/mailboxes/application_mailbox.rb b/sample-app/app/mailboxes/application_mailbox.rb
similarity index 56%
rename from spec/dummy/app/mailboxes/application_mailbox.rb
rename to sample-app/app/mailboxes/application_mailbox.rb
index ac22d03c..53a139c3 100644
--- a/spec/dummy/app/mailboxes/application_mailbox.rb
+++ b/sample-app/app/mailboxes/application_mailbox.rb
@@ -1,3 +1,3 @@
class ApplicationMailbox < ActionMailbox::Base
- # routing /something/i => :somewhere
+ routing /.*/ => :test
end
diff --git a/sample-app/app/mailboxes/test_mailbox.rb b/sample-app/app/mailboxes/test_mailbox.rb
new file mode 100644
index 00000000..2f77e107
--- /dev/null
+++ b/sample-app/app/mailboxes/test_mailbox.rb
@@ -0,0 +1,4 @@
+class TestMailbox < ApplicationMailbox
+ def process
+ end
+end
diff --git a/sample-app/config/environments/development.rb b/sample-app/config/environments/development.rb
index b3b0a8ba..1bcedab6 100644
--- a/sample-app/config/environments/development.rb
+++ b/sample-app/config/environments/development.rb
@@ -1,6 +1,9 @@
require "active_support/core_ext/integer/time"
Rails.application.configure do
+ config.active_storage.service = :local
+ config.action_mailbox.ingress = :ses
+
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded any time
diff --git a/sample-app/config/environments/production.rb b/sample-app/config/environments/production.rb
index 8daf2739..1ae152e7 100644
--- a/sample-app/config/environments/production.rb
+++ b/sample-app/config/environments/production.rb
@@ -1,6 +1,9 @@
require "active_support/core_ext/integer/time"
Rails.application.configure do
+ # Prepare the ingress controller used to receive mail
+ # config.action_mailbox.ingress = :relay
+
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
diff --git a/sample-app/config/initializers/action_mailer.rb b/sample-app/config/initializers/action_mailer.rb
index f0104bae..a6ccf50c 100644
--- a/sample-app/config/initializers/action_mailer.rb
+++ b/sample-app/config/initializers/action_mailer.rb
@@ -1,3 +1,3 @@
options = {}
-ActionMailer::Base.add_delivery_method :ses, Aws::ActionMailer::SESMailer, **options
-ActionMailer::Base.add_delivery_method :ses_v2, Aws::ActionMailer::SESV2Mailer, **options
+ActionMailer::Base.add_delivery_method :ses, Aws::ActionMailer::SES::Mailer, **options
+ActionMailer::Base.add_delivery_method :ses_v2, Aws::ActionMailer::SESV2::Mailer, **options
diff --git a/spec/dummy/config/storage.yml b/sample-app/config/storage.yml
similarity index 89%
rename from spec/dummy/config/storage.yml
rename to sample-app/config/storage.yml
index 6861af3b..ff552906 100644
--- a/spec/dummy/config/storage.yml
+++ b/sample-app/config/storage.yml
@@ -1,3 +1,3 @@
-test:
+local:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
diff --git a/sample-app/db/migrate/20241113202339_create_active_storage_tables.active_storage.rb b/sample-app/db/migrate/20241113202339_create_active_storage_tables.active_storage.rb
new file mode 100644
index 00000000..6bd8bd08
--- /dev/null
+++ b/sample-app/db/migrate/20241113202339_create_active_storage_tables.active_storage.rb
@@ -0,0 +1,57 @@
+# This migration comes from active_storage (originally 20170806125915)
+class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
+ def change
+ # Use Active Record's configured type for primary and foreign keys
+ primary_key_type, foreign_key_type = primary_and_foreign_key_types
+
+ create_table :active_storage_blobs, id: primary_key_type do |t|
+ t.string :key, null: false
+ t.string :filename, null: false
+ t.string :content_type
+ t.text :metadata
+ t.string :service_name, null: false
+ t.bigint :byte_size, null: false
+ t.string :checksum
+
+ if connection.supports_datetime_with_precision?
+ t.datetime :created_at, precision: 6, null: false
+ else
+ t.datetime :created_at, null: false
+ end
+
+ t.index [ :key ], unique: true
+ end
+
+ create_table :active_storage_attachments, id: primary_key_type do |t|
+ t.string :name, null: false
+ t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
+ t.references :blob, null: false, type: foreign_key_type
+
+ if connection.supports_datetime_with_precision?
+ t.datetime :created_at, precision: 6, null: false
+ else
+ t.datetime :created_at, null: false
+ end
+
+ t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
+ t.foreign_key :active_storage_blobs, column: :blob_id
+ end
+
+ create_table :active_storage_variant_records, id: primary_key_type do |t|
+ t.belongs_to :blob, null: false, index: false, type: foreign_key_type
+ t.string :variation_digest, null: false
+
+ t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
+ t.foreign_key :active_storage_blobs, column: :blob_id
+ end
+ end
+
+ private
+ def primary_and_foreign_key_types
+ config = Rails.configuration.generators
+ setting = config.options[config.orm][:primary_key_type]
+ primary_key_type = setting || :primary_key
+ foreign_key_type = setting || :bigint
+ [ primary_key_type, foreign_key_type ]
+ end
+end
diff --git a/sample-app/db/migrate/20241113202340_create_action_mailbox_tables.action_mailbox.rb b/sample-app/db/migrate/20241113202340_create_action_mailbox_tables.action_mailbox.rb
new file mode 100644
index 00000000..7b2b8079
--- /dev/null
+++ b/sample-app/db/migrate/20241113202340_create_action_mailbox_tables.action_mailbox.rb
@@ -0,0 +1,20 @@
+# This migration comes from action_mailbox (originally 20180917164000)
+class CreateActionMailboxTables < ActiveRecord::Migration[6.0]
+ def change
+ create_table :action_mailbox_inbound_emails, id: primary_key_type do |t|
+ t.integer :status, default: 0, null: false
+ t.string :message_id, null: false
+ t.string :message_checksum, null: false
+
+ t.timestamps
+
+ t.index [ :message_id, :message_checksum ], name: "index_action_mailbox_inbound_emails_uniqueness", unique: true
+ end
+ end
+
+ private
+ def primary_key_type
+ config = Rails.configuration.generators
+ config.options[config.orm][:primary_key_type] || :primary_key
+ end
+end
diff --git a/sample-app/db/schema.rb b/sample-app/db/schema.rb
index f7d30f8a..6ee7c2f5 100644
--- a/sample-app/db/schema.rb
+++ b/sample-app/db/schema.rb
@@ -10,7 +10,44 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.2].define(version: 2024_11_06_152613) do
+ActiveRecord::Schema[7.2].define(version: 2024_11_13_202340) do
+ create_table "action_mailbox_inbound_emails", force: :cascade do |t|
+ t.integer "status", default: 0, null: false
+ t.string "message_id", null: false
+ t.string "message_checksum", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["message_id", "message_checksum"], name: "index_action_mailbox_inbound_emails_uniqueness", unique: true
+ end
+
+ create_table "active_storage_attachments", force: :cascade do |t|
+ t.string "name", null: false
+ t.string "record_type", null: false
+ t.bigint "record_id", null: false
+ t.bigint "blob_id", null: false
+ t.datetime "created_at", null: false
+ t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
+ t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
+ end
+
+ create_table "active_storage_blobs", force: :cascade do |t|
+ t.string "key", null: false
+ t.string "filename", null: false
+ t.string "content_type"
+ t.text "metadata"
+ t.string "service_name", null: false
+ t.bigint "byte_size", null: false
+ t.string "checksum"
+ t.datetime "created_at", null: false
+ t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
+ end
+
+ create_table "active_storage_variant_records", force: :cascade do |t|
+ t.bigint "blob_id", null: false
+ t.string "variation_digest", null: false
+ t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
+ end
+
create_table "users", force: :cascade do |t|
t.string "email"
t.string "password_digest"
@@ -18,4 +55,7 @@
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
end
+
+ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
+ add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
end
diff --git a/sample-app/storage/development.sqlite3 b/sample-app/storage/development.sqlite3
index 189f5763..92122c7c 100644
Binary files a/sample-app/storage/development.sqlite3 and b/sample-app/storage/development.sqlite3 differ
diff --git a/sample-app/test/mailboxes/test_mailbox_test.rb b/sample-app/test/mailboxes/test_mailbox_test.rb
new file mode 100644
index 00000000..d9840536
--- /dev/null
+++ b/sample-app/test/mailboxes/test_mailbox_test.rb
@@ -0,0 +1,11 @@
+require "test_helper"
+
+class TestMailboxTest < ActionMailbox::TestCase
+ # test "receive mail" do
+ # receive_inbound_email_from_mail \
+ # to: '"someone" ',
+ # from: '"else" ',
+ # subject: "Hello world!",
+ # body: "Hello?"
+ # end
+end
diff --git a/spec/aws/rails/action_mailbox/requests/inbound_email_spec.rb b/spec/aws/rails/action_mailbox/requests/inbound_email_spec.rb
deleted file mode 100644
index d40d3428..00000000
--- a/spec/aws/rails/action_mailbox/requests/inbound_email_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require 'test_helper'
-
-describe 'inbound email', type: :request do
- let(:inbound_email_url) { '/rails/action_mailbox/ses/inbound_emails' }
-
- before do
- stub_request(
- :get,
- 'https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem'
- ).and_return(body: fixture_for(:certificate, type: :pem))
- end
-
- it 'receives inbound email' do
- post inbound_email_url, params: JSON.parse(fixture_for(:inbound_email, type: :json)), as: :json
-
- expect(response).to have_http_status(:no_content)
- expect(ActionMailbox::InboundEmail.count).to eql 1
- end
-
- it 'receives an inbound email with data in s3' do
- s3_email = fixture_for(:s3_email, type: :txt)
-
- s3_client = Aws::S3::Client.new(stub_responses: true)
- s3_client.stub_responses(:head_object, { content_length: s3_email.size, parts_count: 1 })
- s3_client.stub_responses(:get_object, { body: s3_email })
-
- allow(Aws::S3::Client).to receive(:new).and_return(s3_client)
-
- expect do
- post inbound_email_url,
- params: JSON.parse(fixture_for(:inbound_email_s3, type: :json)),
- as: :json
- end.to change(ActionMailbox::InboundEmail, :count).by(1)
-
- expect(response).to have_http_status(:no_content)
-
- inbound_email = ActionMailbox::InboundEmail.last
- expect(s3_email).to eq(inbound_email.raw_email.download)
- end
-end
diff --git a/spec/aws/rails/action_mailbox/requests/rspec_spec.rb b/spec/aws/rails/action_mailbox/requests/rspec_spec.rb
deleted file mode 100644
index 356eeded..00000000
--- a/spec/aws/rails/action_mailbox/requests/rspec_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-require 'test_helper'
-require 'aws/rails/action_mailbox/rspec'
-
-describe 'rspec', type: :request do
- include Aws::Rails::ActionMailbox::RSpec
-
- before do
- allow(Rails.configuration.action_mailbox.ses).to receive(:subscribed_topic) { topic }
- end
-
- describe 'topic subscription' do
- describe 'recognized topic' do
- let(:topic) { 'topic:arn:default' }
- it 'renders 200 OK' do
- action_mailbox_ses_deliver_subscription_confirmation
- expect(response).to have_http_status :ok
- end
- end
-
- describe 'unrecognized topic' do
- let(:topic) { 'topic:arn:other' }
- it 'renders 401 Unauthorized' do
- action_mailbox_ses_deliver_subscription_confirmation
- expect(response).to have_http_status :unauthorized
- end
- end
- end
-
- describe 'email delivery' do
- describe 'when recognized topic' do
- let(:topic) { 'topic:arn:default' }
- it 'renders 204 No Content' do
- action_mailbox_ses_deliver_email(mail: Mail.new)
- expect(response).to have_http_status :no_content
- end
-
- it 'delivers an email to inbox' do
- action_mailbox_ses_deliver_email(mail: Mail.new(to: 'user@example.com'))
- expect(ActionMailbox::InboundEmail.last.mail.recipients).to eql ['user@example.com']
- end
- end
-
- describe 'when unrecognized topic' do
- let(:topic) { 'topic:arn:other' }
- it 'renders 401 Unauthorized' do
- action_mailbox_ses_deliver_email
- expect(response).to have_http_status :unauthorized
- end
- end
-
- describe 'with destination parameter set' do
- let(:topic) { 'topic:arn:default' }
-
- it 'extracts recipient email from SNS notification content' do
- action_mailbox_ses_deliver_email(
- mail: Mail.new(to: 'user@example.com'),
- message_params: { 'mail' => { 'destination' => ['bcc_user@example.com'] } }
- )
-
- expect(ActionMailbox::InboundEmail.last.mail.recipients).to contain_exactly(
- 'user@example.com', 'bcc_user@example.com'
- )
- end
- end
- end
-end
diff --git a/spec/aws/rails/action_mailbox/requests/subscription_confirmation_spec.rb b/spec/aws/rails/action_mailbox/requests/subscription_confirmation_spec.rb
deleted file mode 100644
index 27889d36..00000000
--- a/spec/aws/rails/action_mailbox/requests/subscription_confirmation_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-require 'test_helper'
-
-describe 'subscription confirmation', type: :request do
- let!(:subscription_confirmation_request) do
- query = Rack::Utils.build_query(subscription_params)
- stub_request(:get, "https://sns.eu-west-1.amazonaws.com/?#{query}")
- end
-
- let(:subscription_params) do
- {
- Action: 'ConfirmSubscription',
- Token: 'abcd1234' * 32,
- TopicArn: "arn:aws:sns:eu-west-1:012345678910:#{topic}"
- }
- end
-
- let(:topic) { 'example-topic' }
-
- let(:action) do
- post '/rails/action_mailbox/ses/inbound_emails',
- headers: { 'Content-Type' => 'application/json' },
- params: fixture_for(type, type: :json)
- end
-
- before do
- stub_request(
- :get,
- 'https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem'
- ).and_return(body: fixture_for(:certificate, type: :pem))
- end
-
- context 'when valid Amazon SSL signature' do
- let(:type) { 'valid_signature' }
-
- it 'fetches subscription URL' do
- action
- expect(subscription_confirmation_request).to have_been_requested
- end
- end
-
- context 'when invalid Amazon SSL signature' do
- let(:type) { 'invalid_signature' }
-
- it 'does not fetch subscription URL' do
- action
- expect(subscription_confirmation_request).to_not have_been_requested
- end
- end
-
- context 'when unrecognized topic' do
- let(:type) { 'unrecognized_topic_subscription_request' }
- let(:topic) { 'unrecognized-topic' }
-
- it 'does not fetch subscription URL' do
- action
- expect(subscription_confirmation_request).to_not have_been_requested
- end
- end
-end
diff --git a/spec/aws/rails/action_mailbox/rspec/email_spec.rb b/spec/aws/rails/action_mailbox/rspec/email_spec.rb
deleted file mode 100644
index 366e2a37..00000000
--- a/spec/aws/rails/action_mailbox/rspec/email_spec.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-require 'test_helper'
-
-describe Aws::Rails::ActionMailbox::RSpec::Email do
- let(:email) { described_class.new(authentic: authentic, mail: mail, topic: topic) }
- let(:topic) { 'topic:arn:default' }
- let(:authentic) { true }
- let(:mail) { instance_double(Mail::Message, encoded: 'raw encoded email') }
- let(:expected_params) do
- {
- 'Type' => 'Notification',
- 'TopicArn' => topic,
- 'Message' => {
- 'notificationType' => 'Received',
- 'content' => 'raw encoded email'
- }.to_json
- }
- end
-
- it 'has the correct data' do
- expect(email.url).to eq('/rails/action_mailbox/ses/inbound_emails')
- expect(email.headers).to eq('content-type' => 'application/json')
- expect(email.params).to eq(expected_params)
- end
-
- describe '#authentic?' do
- subject(:email_authentic) { email.authentic? }
-
- context 'when authentic' do
- let(:authentic) { true }
-
- it { is_expected.to be(true) }
- end
-
- context 'when not authentic' do
- let(:authentic) { false }
-
- it { is_expected.to be(false) }
- end
- end
-
- context 'when custom topic' do
- let(:topic) { 'custom-topic' }
-
- it 'has topic' do
- expect(email.params).to include('TopicArn' => topic)
- end
- end
-end
diff --git a/spec/aws/rails/action_mailbox/rspec/subscription_confirmation_spec.rb b/spec/aws/rails/action_mailbox/rspec/subscription_confirmation_spec.rb
deleted file mode 100644
index 10512f56..00000000
--- a/spec/aws/rails/action_mailbox/rspec/subscription_confirmation_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-require 'test_helper'
-
-describe Aws::Rails::ActionMailbox::RSpec::SubscriptionConfirmation do
- let(:subscription) { described_class.new(authentic: authentic, topic: topic) }
-
- let(:authentic) { true }
- let(:topic) { 'topic:arn:default' }
- let(:expected_params) do
- {
- 'Type' => 'SubscriptionConfirmation',
- 'TopicArn' => topic,
- 'SubscribeURL' => 'http://example.com/subscribe'
- }
- end
-
- it 'has the correct data' do
- expect(subscription.url).to eq('/rails/action_mailbox/ses/inbound_emails')
- expect(subscription.headers).to eq('content-type' => 'application/json')
- expect(subscription.params).to eq(expected_params)
- end
-
- describe '#authentic?' do
- subject(:subscription_authentic) { subscription.authentic? }
-
- context 'when authentic' do
- let(:authentic) { true }
-
- it { is_expected.to be(true) }
- end
-
- context 'when not authentic' do
- let(:authentic) { false }
-
- it { is_expected.to be(false) }
- end
- end
-
- context 'when custom topic' do
- let(:topic) { 'custom-topic' }
-
- it 'has topic' do
- expect(subscription.params).to include('TopicArn' => topic)
- end
- end
-end
diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb
index 865d1e87..a2a62377 100644
--- a/spec/dummy/config/application.rb
+++ b/spec/dummy/config/application.rb
@@ -1,12 +1,10 @@
# frozen_string_literal: true
require 'rails'
-require 'activerecord-jdbc-adapter' if defined? JRUBY_VERSION
require 'active_job/railtie'
require 'action_controller/railtie'
require 'action_mailer/railtie'
require 'action_view/railtie'
-require 'action_mailbox/engine'
require 'aws-sdk-rails'
module Dummy
diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml
deleted file mode 100644
index 800589fa..00000000
--- a/spec/dummy/config/database.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- adapter: sqlite3
- database: db/test.db
diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb
index e10d3fa5..f5fd48f4 100644
--- a/spec/dummy/config/environments/test.rb
+++ b/spec/dummy/config/environments/test.rb
@@ -1,7 +1,4 @@
Rails.application.configure do
- config.active_storage.service = :test
- config.action_mailbox.ingress = :ses
- config.action_mailbox.ses.subscribed_topic = 'arn:aws:sns:eu-west-1:012345678910:example-topic'
config.action_dispatch.show_exceptions = :none
config.eager_load = true
end
diff --git a/spec/fixtures/json/inbound_email.json b/spec/fixtures/json/inbound_email.json
deleted file mode 100644
index 91d30ff4..00000000
--- a/spec/fixtures/json/inbound_email.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Type": "Notification",
- "MessageId": "abc12345-abc1-abc1-abc1-abc123456789",
- "TopicArn": "arn:aws:sns:eu-west-1:012345678910:example-topic",
- "Subject": "Amazon SES Email Receipt Notification",
- "Message": "{\"notificationType\":\"Received\",\"mail\":{\"timestamp\":\"2020-05-09T09:16:15.982Z\",\"source\":\"sender@example.com\",\"messageId\":\"abcdef0123456789abcdef0123456789abcdef01\",\"destination\":[\"recipient@example.com\"],\"headersTruncated\":false,\"headers\":[{\"name\":\"Return-Path\",\"value\":\"\"},{\"name\":\"Received\",\"value\":\"from mail.example.com (mail.example.com [1.2.3.4]) by inbound-smtp.eu-west-1.amazonaws.com with SMTP id abcdef0123456789abcdef0123456789abcdef01 for recipient@example.com; Sat, 09 May 2020 09:16:15 +0000 (UTC)\"},{\"name\":\"X-SES-Spam-Verdict\",\"value\":\"PASS\"},{\"name\":\"X-SES-Virus-Verdict\",\"value\":\"PASS\"},{\"name\":\"Received-SPF\",\"value\":\"pass (spfCheck: domain of example.com designates 1.2.3.4 as permitted sender) client-ip=5.5.5.5; envelope-from=sender@example.com; helo=mail.example.com;\"},{\"name\":\"Authentication-Results\",\"value\":\"amazonses.com; spf=pass (spfCheck: domain of example.com designates 5.5.5.5 as permitted sender) client-ip=5.5.5.5; envelope-from=sender@example.com; helo=mail.example.com; dkim=pass header.i=@example.com; dmarc=none header.from=example.com;\"},{\"name\":\"X-SES-RECEIPT\",\"value\":\"AEFBQUFBQUFBQUFFNkFrOCtYbmRzcE13djhXN3hhOEttYU02NUhLMGZYYzBpQUx4SG5wcEI5KzNQakdHTWNEbjExMTlnRlNBbWNsVVFJd2YzQjY1RU5aeGM5dzdlbE9wcmpibjNSZ2NBMmx6dmJhQmM3SmxDdmljc25KUnpuTlpSdnhhVkx6MFRpc2dXWTFZY3RFU2hXcUs1YllxZ1RVUFo3cmJaN0NpeTU3VjhtN1liclpYVXN4K3lmWm5FQ1B6dkp5b3hsQ3pJd3VUUWd4M3lzSm1uc0QzQVRieE1FTGdMdFU5anA2Z2RUKzEyOVZYV1ZyN0hHNHR6SURBSUI4VkxaVEJqaHhRWTRqenltKzIyTG9IaWYwM1huVVlIK1ZGMmNBazc4dVdCaUNkQmtIcWd1VWs2M0E9PQ==\"},{\"name\":\"X-SES-DKIM-SIGNATURE\",\"value\":\"a=rsa-sha256; q=dns/txt; b=XH7Cy8VtplePQbGI2JndadMaSQRzuFCUCQl3RRIFpN+eZgS06eyYut3gar8ds6b1mHzNwSsBB5cj5YAF/GompbFbWV2GL04XqDSxvfrdlTkv+qA0SQLnveyFUDJTKlPPr8TjF2G+k2s8BFgchLyR+IBbmPHeH+jNknvqNArh77w=; c=relaxed/simple; s=shh3fegwg5fppqsuzphvschd53n6ihuv; d=amazonses.com; t=1589015776; v=1; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;\"},{\"name\":\"Received\",\"value\":\"by mail-oi1-f180.google.com with SMTP id o7so10735431oif.2 for ; Sat, 09 May 2020 02:16:15 -0700 (PDT)\"},{\"name\":\"DKIM-Signature\",\"value\":\"v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=google; h=mime-version:from:date:message-id:subject:to; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; b=Vg0zgLNrgypVuHn7dOM1j1xZz9zifdKm/8BJSVCZMPza8e5bsCI/MOPqQxv8KaKTOZKPpq2uNMhw/ueG/bc04WvoJrYX3/vAzMDXLf8oPvLuLyjfaePc68hSQr5fHzOxzmuLei9sKo7CthTQIrW0s1a27xWHc3UT96fEdw2BdSI=\"},{\"name\":\"X-Google-DKIM-Signature\",\"value\":\"v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; b=sINpYmONoM0qeQnebY9hQK4EtWUq8xq5tnbjE7box8LHPsGMrrQyIiH9/IIbiH7oUg NE0FItezKdzD4RiOh3C48RpvrP7yGg3w9n3FyuJ/8JjJ6endtnGRwIma3LkJygz+3FzE Sire7dZVCwij0WquBXJ2WKjemFiPPg6M002pYD8F6ZpNPjuL1+qtUiLoSUGFy6hYvMNa FVRUyVZil8Sd6n3DL5R3FhVSNB1MptWm2CTIgv2+dEyXf5cO0sn6LDPgO3Jx2LO5/oyn +SdNJsc86nbXEjA7aL9pMlU0YdRMIbpwYHPvvyWT3K5hB6wnYF+hAyTn454ACXdduYi3 E72g==\"},{\"name\":\"X-Gm-Message-State\",\"value\":\"AGi0PuZnRiX/3B0rQ6UV4cR4oucLl9xNu5Vm2LQzGB+wZPNGquEwxctp xqfK7mfh70F01tIxZ1H74HKDGTD71OiJ6e9D8hHn+J8t\"},{\"name\":\"X-Google-Smtp-Source\",\"value\":\"APiQypJYIgvF7HgWijswlpCCmdg46BkfhUhhqSk1JllbbMoxs1ntBGx8iXfpjMD1ton1sdL3L4HFJsawRsBwK4+ZDF4=\"},{\"name\":\"X-Received\",\"value\":\"by 2002:aca:ba86:: with SMTP id k128mr13817762oif.60.1589015774221; Sat, 09 May 2020 02:16:14 -0700 (PDT)\"},{\"name\":\"MIME-Version\",\"value\":\"1.0\"},{\"name\":\"From\",\"value\":\"Email Sender \"},{\"name\":\"Date\",\"value\":\"Sat, 9 May 2020 10:16:03 +0100\"},{\"name\":\"Message-ID\",\"value\":\"\"},{\"name\":\"Subject\",\"value\":\"testing\"},{\"name\":\"To\",\"value\":\"recipient@example.com\"},{\"name\":\"Content-Type\",\"value\":\"multipart/alternative; boundary=\\\"000000000000c3f47c05a533908c\\\"\"}],\"commonHeaders\":{\"returnPath\":\"sender@example.com\",\"from\":[\"Email Sender \"],\"date\":\"Sat, 9 May 2020 10:16:03 +0100\",\"to\":[\"recipient@example.com\"],\"messageId\":\"\",\"subject\":\"testing\"}},\"receipt\":{\"timestamp\":\"2020-05-09T09:16:15.982Z\",\"processingTimeMillis\":414,\"recipients\":[\"recipient@example.com\"],\"spamVerdict\":{\"status\":\"PASS\"},\"virusVerdict\":{\"status\":\"PASS\"},\"spfVerdict\":{\"status\":\"PASS\"},\"dkimVerdict\":{\"status\":\"PASS\"},\"dmarcVerdict\":{\"status\":\"GRAY\"},\"action\":{\"type\":\"SNS\",\"topicArn\":\"arn:aws:sns:eu-west-1:012345678910:example-topic\",\"encoding\":\"UTF8\"}},\"content\":\"Return-Path: \\r\\nReceived: from mail-oi1-f180.google.com (mail-oi1-f180.google.com [209.85.167.180])\\r\\n by inbound-smtp.eu-west-1.amazonaws.com with SMTP id 7nt592nn42m2fh53jk2vmig13rvr5hdm5i31ca01\\r\\n for recipient@example.com;\\r\\n Sat, 09 May 2020 09:16:15 +0000 (UTC)\\r\\nX-SES-Spam-Verdict: PASS\\r\\nX-SES-Virus-Verdict: PASS\\r\\nReceived-SPF: pass (spfCheck: domain of example.com designates 209.85.167.180 as permitted sender) client-ip=209.85.167.180; envelope-from=sender@example.com; helo=mail-oi1-f180.google.com;\\r\\nAuthentication-Results: amazonses.com;\\r\\n spf=pass (spfCheck: domain of example.com designates 209.85.167.180 as permitted sender) client-ip=209.85.167.180; envelope-from=sender@example.com; helo=mail-oi1-f180.google.com;\\r\\n dkim=pass header.i=@example.com;\\r\\n dmarc=none header.from=example.com;\\r\\nX-SES-RECEIPT: AEFBQUFBQUFBQUFFNkFrOCtYbmRzcE13djhXN3hhOEttYU02NUhLMGZYYzBpQUx4SG5wcEI5KzNQakdHTWNEbjExMTlnRlNBbWNsVVFJd2YzQjY1RU5aeGM5dzdlbE9wcmpibjNSZ2NBMmx6dmJhQmM3SmxDdmljc25KUnpuTlpSdnhhVkx6MFRpc2dXWTFZY3RFU2hXcUs1YllxZ1RVUFo3cmJaN0NpeTU3VjhtN1liclpYVXN4K3lmWm5FQ1B6dkp5b3hsQ3pJd3VUUWd4M3lzSm1uc0QzQVRieE1FTGdMdFU5anA2Z2RUKzEyOVZYV1ZyN0hHNHR6SURBSUI4VkxaVEJqaHhRWTRqenltKzIyTG9IaWYwM1huVVlIK1ZGMmNBazc4dVdCaUNkQmtIcWd1VWs2M0E9PQ==\\r\\nX-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=XH7Cy8VtplePQbGI2JndadMaSQRzuFCUCQl3RRIFpN+eZgS06eyYut3gar8ds6b1mHzNwSsBB5cj5YAF/GompbFbWV2GL04XqDSxvfrdlTkv+qA0SQLnveyFUDJTKlPPr8TjF2G+k2s8BFgchLyR+IBbmPHeH+jNknvqNArh77w=; c=relaxed/simple; s=shh3fegwg5fppqsuzphvschd53n6ihuv; d=amazonses.com; t=1589015776; v=1; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;\\r\\nReceived: by mail-oi1-f180.google.com with SMTP id o7so10735431oif.2\\r\\n for ; Sat, 09 May 2020 02:16:15 -0700 (PDT)\\r\\nDKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\\r\\n d=example.com; s=google;\\r\\n h=mime-version:from:date:message-id:subject:to;\\r\\n bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=;\\r\\n b=Vg0zgLNrgypVuHn7dOM1j1xZz9zifdKm/8BJSVCZMPza8e5bsCI/MOPqQxv8KaKTOZ\\r\\n KPpq2uNMhw/ueG/bc04WvoJrYX3/vAzMDXLf8oPvLuLyjfaePc68hSQr5fHzOxzmuLei\\r\\n 9sKo7CthTQIrW0s1a27xWHc3UT96fEdw2BdSI=\\r\\nX-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\\r\\n d=1e100.net; s=20161025;\\r\\n h=x-gm-message-state:mime-version:from:date:message-id:subject:to;\\r\\n bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=;\\r\\n b=sINpYmONoM0qeQnebY9hQK4EtWUq8xq5tnbjE7box8LHPsGMrrQyIiH9/IIbiH7oUg\\r\\n NE0FItezKdzD4RiOh3C48RpvrP7yGg3w9n3FyuJ/8JjJ6endtnGRwIma3LkJygz+3FzE\\r\\n Sire7dZVCwij0WquBXJ2WKjemFiPPg6M002pYD8F6ZpNPjuL1+qtUiLoSUGFy6hYvMNa\\r\\n FVRUyVZil8Sd6n3DL5R3FhVSNB1MptWm2CTIgv2+dEyXf5cO0sn6LDPgO3Jx2LO5/oyn\\r\\n +SdNJsc86nbXEjA7aL9pMlU0YdRMIbpwYHPvvyWT3K5hB6wnYF+hAyTn454ACXdduYi3\\r\\n E72g==\\r\\nX-Gm-Message-State: AGi0PuZnRiX/3B0rQ6UV4cR4oucLl9xNu5Vm2LQzGB+wZPNGquEwxctp\\r\\n\\txqfK7mfh70F01tIxZ1H74HKDGTD71OiJ6e9D8hHn+J8t\\r\\nX-Google-Smtp-Source: APiQypJYIgvF7HgWijswlpCCmdg46BkfhUhhqSk1JllbbMoxs1ntBGx8iXfpjMD1ton1sdL3L4HFJsawRsBwK4+ZDF4=\\r\\nX-Received: by 2002:aca:ba86:: with SMTP id k128mr13817762oif.60.1589015774221;\\r\\n Sat, 09 May 2020 02:16:14 -0700 (PDT)\\r\\nMIME-Version: 1.0\\r\\nFrom: Email Sender \\r\\nDate: Sat, 9 May 2020 10:16:03 +0100\\r\\nMessage-ID: \\r\\nSubject: testing\\r\\nTo: recipient@example.com\\r\\nContent-Type: multipart/alternative; boundary=\\\"000000000000c3f47c05a533908c\\\"\\r\\n\\r\\n--000000000000c3f47c05a533908c\\r\\nContent-Type: text/plain; charset=\\\"UTF-8\\\"\\r\\n\\r\\ntest message\\r\\n\\r\\n--000000000000c3f47c05a533908c\\r\\nContent-Type: text/html; charset=\\\"UTF-8\\\"\\r\\n\\r\\ntest message
\\r\\n\\r\\n--000000000000c3f47c05a533908c--\\r\\n\"}",
- "Timestamp": "2020-05-09T09:16:16.406Z",
- "SignatureVersion": "1",
- "Signature": "0Qyky3c4BopZI4B0dGGgZJxR56ayW4j9Pulx/+z7bs+KsRuOew8zHkCuEil4\nLZ75+9Xtt5dJRbtV0FZXF7m80PwiB0n0XfMuLCALqWtuki+4oxnVn+vFHCxR\n/96EVmrd/bOT9wwaQ5xmaku1bmXyYUiXCGr5I0VLMGENT6dlL/Nu1bI7WTOf\nLI3DV8ed8UCCgwYCZlVJqQbUwBjZsZRWFelk2dsH23TT0kH7emU4HYPm9Rpp\ngXZkz5VzPuT0xTYcQ9iLpw6CLNRn1RSYHmpf0rGnt5xXgsT6rHdqmCOII280\nxILxGdOo+wnwZC1txZ3D1e/BfqztexZpG/6pQZfyXw==\n",
- "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem",
- "UnsubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:012345678910:example-topic:abcdef01-abc1-abc1-abc1-abcdef123456"
-}
\ No newline at end of file
diff --git a/spec/fixtures/json/inbound_email_s3.json b/spec/fixtures/json/inbound_email_s3.json
deleted file mode 100644
index 55f3c6ff..00000000
--- a/spec/fixtures/json/inbound_email_s3.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Type": "Notification",
- "MessageId": "abc12345-abc1-abc1-abc1-abc123456789",
- "TopicArn": "arn:aws:sns:eu-west-1:012345678910:example-topic",
- "Subject": "Amazon SES Email Receipt Notification",
- "Message": "{\"notificationType\":\"Received\",\"mail\":{\"timestamp\":\"2020-09-02T01:30:50.233Z\",\"source\":\"sender@example.com\",\"messageId\":\"17at0jiq08p0449huhf16qsmdi6sa1ltm069t801\",\"destination\":[\"recipient@example.com\"],\"headersTruncated\":false,\"headers\":[{\"name\":\"Return-Path\",\"value\":\"\"},{\"name\":\"Received\",\"value\":\"from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11on2115.outbound.protection.outlook.com [40.107.223.115]) by inbound-smtp.us-east-1.amazonaws.com with SMTP id 17at0jiq08p0449huhf16qsmdi6sa1ltm069t801 for recipient@example.com; Wed, 02 Sep 2020 01:30:50 +0000 (UTC)\"},{\"name\":\"X-SES-Spam-Verdict\",\"value\":\"PASS\"},{\"name\":\"X-SES-Virus-Verdict\",\"value\":\"PASS\"},{\"name\":\"Received-SPF\",\"value\":\"none (spfCheck: 40.107.223.115 is neither permitted nor denied by domain of uiowa.edu) client-ip=40.107.223.115; envelope-from=sender@example.com; helo=mail-dm6nam11on2115.outbound.protection.outlook.com;\"},{\"name\":\"Authentication-Results\",\"value\":\"amazonses.com; spf=none (spfCheck: 40.107.223.115 is neither permitted nor denied by domain of uiowa.edu) client-ip=40.107.223.115; envelope-from=sender@example.com; helo=mail-dm6nam11on2115.outbound.protection.outlook.com; dkim=pass header.i=@iowa.onmicrosoft.com; dmarc=fail header.from=uiowa.edu;\"},{\"name\":\"X-SES-RECEIPT\",\"value\":\"AEFBQUFBQUFBQUFHMWlxem9Gb1ZOemNkamlTeFlYdlZUSmUwVVZhYndjK213dHFIM0dVRTYwUlk1UlpBQVVVTXhQRUd1MTN6YTFJalp0TFdMZjhOOUZGSlJCYkxEV2craXhpOG02d2xDc2FtY2dNdVMvRE9QWWpNVkxBWVZzMyt5MHBTUXV5KzM5aDY1Vng5UnZsZTdTK2dGVDF5RVc1QndOd0xvbndNRlR3TDZjd2cxT2c2UVFQbVN2andMS09VM2R5elFrTGk3RnF0WXI3WDZ1alhkUzJxdzhzU1dwT3FPZEFsU0VNc3RpTWM0QStFZDB5RFd5SnpRelBJWnJjelZPRytudEVpNTc5dVZRUXMra2lrby9wOExhR3JqTi9xNkZnNHREN3BmSmVYS25Jeis2NDRyaEE9PQ==\"},{\"name\":\"X-SES-DKIM-SIGNATURE\",\"value\":\"a=rsa-sha256; q=dns/txt; b=WGBoUguIq9047YXpCaubVCtm/ISR3JEVkvm/yAfL2MrAryQcYsTdUM6zzStPyvOm0QsonOKsWJ0O2YyuQDX1dvBmggdeUqZq08laD+Xuy1L6ODm0O/EQE9wDitj0KqXxOgMr3oM7tpcTTGLcCgXERFZbmI+1ACeeA7fbylMasIM=; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1599010250; v=1; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;\"},{\"name\":\"ARC-Seal\",\"value\":\"i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Q/Sjx2jglTDjAuzScT/G47EngqUbAoJ6QRr1YXHzCJo7FLHyH16OuE+DmmOqQGiiAQjV4jooqaOGMg/iYLGvebTH3O//kXe1LfK+b6Ixwrom9B2X0KkHdBrRrbtD503NjUGzbjXruZVDajQnhmjA79YhqedZPTfrz7OijinyTQNLWhtp5JrC9olVfGNGvj9h1kU7t2j6sWc/8Fi9REDT/HYEJOBxwSoKVcDtyGw9+3D/RhrTGycE0xcWWmtgAgDmmGzvhXef/FBENzObP3VPMeSyty2Lr/j8nxgtnC4Lv/SFE4eKIVAMbabN26Oqbe4ZaRjlouqVJuDUm5ZS/9NE2w==\"},{\"name\":\"ARC-Message-Signature\",\"value\":\"i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; b=a75mHcfAxpG1bEdE+DrfQxdjffOeG5B90ORE3hHh4zwotRp0S4ZHYCZmDBEEsk6QeF92941w7fDQuNxdto+Ah309oHlfxvuJT+EYNNvFAdGY1y7zUQGV0a7OfquOU8FWgchRUkz09vVtfFxiF9znbApaWpIbsVXeZ1+D3JcVsUXEpENNSOn+jYZEA30VlKNRESzHeAnniWn5E6FlQfQebRpgHTx3iGo0r1ykVq0pzzDrVsB9308U/TivWqoGVvhEy5ocx8Lx6I12pAny6XoD8RQRjxanteJG8hSzPuNJLqrcLeJTeC+/vDytmRd9WHjF3XlqfrZh3Q2A+nn1dY0LUg==\"},{\"name\":\"ARC-Authentication-Results\",\"value\":\"i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=uiowa.edu; dmarc=pass action=none header.from=uiowa.edu; dkim=pass header.d=uiowa.edu; arc=none\"},{\"name\":\"DKIM-Signature\",\"value\":\"v=1; a=rsa-sha256; c=relaxed/relaxed; d=iowa.onmicrosoft.com; s=selector2-iowa-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; b=UWYfhLXbr1DsFV4wrrkIF4AqHgLrYQvwUdnGvSdvjv1F5Gc/0UzgvxVxmmeJ4Zf/j4AK3itFqt78HuyfOu32ofFFiZ9YIGrUZLF6XBb/cxqo+B1sF8qObP7QB4G8EpcswBtutMHMgX3WMNm3R637j7Xxho7TUWmKoD+Y758WDxk=\"},{\"name\":\"Received\",\"value\":\"from BN6PR04MB0962.namprd04.prod.outlook.com (2603:10b6:405:3e::26) by BN6PR04MB1172.namprd04.prod.outlook.com (2603:10b6:404:97::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3326.19; Wed, 2 Sep 2020 01:30:43 +0000\"},{\"name\":\"Received\",\"value\":\"from BN6PR04MB0962.namprd04.prod.outlook.com ([fe80::81b1:3359:e0e8:7ef4]) by BN6PR04MB0962.namprd04.prod.outlook.com ([fe80::81b1:3359:e0e8:7ef4%5]) with mapi id 15.20.3326.025; Wed, 2 Sep 2020 01:30:43 +0000\"},{\"name\":\"From\",\"value\":\"\\\"Sender\\\" \"},{\"name\":\"To\",\"value\":\"\\\"recipient@example.com\\\" \"},{\"name\":\"Subject\",\"value\":\"Test 500\"},{\"name\":\"Thread-Topic\",\"value\":\"Test 500\"},{\"name\":\"Thread-Index\",\"value\":\"AQHWgMisvDz2gn/lKEK/giPayBxk7g==\"},{\"name\":\"Date\",\"value\":\"Wed, 2 Sep 2020 01:30:43 +0000\"},{\"name\":\"Message-ID\",\"value\":\"<1344C740-07D3-476E-BEE7-6EB162294DF6@uiowa.edu>\"},{\"name\":\"Accept-Language\",\"value\":\"en-US\"},{\"name\":\"Content-Language\",\"value\":\"en-US\"},{\"name\":\"X-MS-Has-Attach\",\"value\":\"\"},{\"name\":\"X-MS-TNEF-Correlator\",\"value\":\"\"},{\"name\":\"x-mailer\",\"value\":\"Apple Mail (2.3608.120.23.2.1)\"},{\"name\":\"authentication-results\",\"value\":\"icts-oasis-aya.aws.cloud.uiowa.edu; dkim=none (message not signed) header.d=none;icts-oasis-aya.aws.cloud.uiowa.edu; dmarc=none action=none header.from=uiowa.edu;\"},{\"name\":\"x-originating-ip\",\"value\":\"[208.126.206.243]\"},{\"name\":\"x-ms-publictraffictype\",\"value\":\"Email\"},{\"name\":\"x-ms-office365-filtering-correlation-id\",\"value\":\"6ec767f9-50fe-47f8-f3f2-08d84edfcf64\"},{\"name\":\"x-ms-traffictypediagnostic\",\"value\":\"BN6PR04MB1172:\"},{\"name\":\"x-microsoft-antispam-prvs\",\"value\":\"\"},{\"name\":\"x-ms-oob-tlc-oobclassifiers\",\"value\":\"OLM:1728;\"},{\"name\":\"x-ms-exchange-senderadcheck\",\"value\":\"1\"},{\"name\":\"x-microsoft-antispam\",\"value\":\"BCL:0;\"},{\"name\":\"x-microsoft-antispam-message-info\",\"value\":\"HpEwIChVAhsQnQ3n5mZXWg906Tt+O7BVntxsud4Ur/yuUGPG4p0kH9GZCWshG/hT0+S/B+zgZ+LPmjIXZ2RKea4J3RQZrT2xuBZ9wUvkwSEF8Su1xvMVqqtoSGsayne41kRtpWEXo82HYqRYA9wWZuUsCpug4QOTN/ivvbEqCzKEEf+VrJ2WAzTD3qYJVqzdxlo4CJav7MXOdM4DaTBPgkEvI7arkhnJVwvrfW+SKrMAT7SdUX9jPk/mveWiiwCyfMG/9mQPLW241uWnoRIY1ruXUmCgUrcWzIw4DYfDpFnvPHtJlZiHmvN3MXAYKysyT4jlS1+2g2SQ3FSZ7y4xJg==\"},{\"name\":\"x-forefront-antispam-report\",\"value\":\"CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:BN6PR04MB0962.namprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(4636009)(39860400002)(376002)(136003)(396003)(366004)(346002)(478600001)(2616005)(8676002)(6512007)(26005)(186003)(75432002)(66476007)(64756008)(66446008)(6506007)(6486002)(66946007)(91956017)(76116006)(66556008)(6916009)(2906002)(36756003)(8936002)(7116003)(316002)(558084003)(296002)(71200400001)(86362001)(19618925003)(33656002)(786003)(239884005)(558944008)(19559445001)(15288005002);DIR:OUT;SFP:1102;\"},{\"name\":\"x-ms-exchange-antispam-messagedata\",\"value\":\"UWWfowj4v8QhFJ48meC6ss7DXF28aXo/r7e6BUMtRz53j+lxuv9earKL7TTePwyVwaU3DHCfwCbNuuhej7zI6sJrn9eV81CVEjR29vZoVPtCgdyMQ/ah/ksInpHswnADVEu0hcs8oVQByrhnT7QRQfowYJC3FBeOta2/Vy2zf8TsfY32ddQdBr3qT2akkJp34AI1GDKgCqZKgojFTw5Lp08YJ9VMNXxCChQbnrtUSBOn+jTMU9/NuDazCrQ/HQGZm3WTaq6Z97MBYwMyeGUmhlT/h3lUVC+5r59NYofVentjcGPSQS7NQ7T5QLfM6JymE9dNR43zIK2nfL713wtC70cfNrQjrEXB0uX7pjLfVeWm4zamJa3kGj9ca/FaAY/ZUv9S3dte3r/I9Tj7SxJk5d7E6IHcq+YoDL/X35N1/+0DQ4JRsCL32AomZHS2+EoSMMjyjatEn/EHngMmD60Zrnr8GKQz7RuuAvCsW5EFzeuPNv2ZvBV2iXe5FyCpXXMI5Ka+4ETl43YZLH8GqGAARkaShPO4W9fnJ/TwDqsERyLm1epqB71M9r+359eA1bMGqfRb0B8IMDYOav3/8216r1vJPi81JN6QVNIJi/FbUDwJ9CespzH7QlTrlvgq/N8ksQqveVv5K38LfIG7CJULaA==\"},{\"name\":\"x-ms-exchange-transport-forked\",\"value\":\"True\"},{\"name\":\"Content-Type\",\"value\":\"text/plain; charset=\\\"us-ascii\\\"\"},{\"name\":\"Content-ID\",\"value\":\"\"},{\"name\":\"Content-Transfer-Encoding\",\"value\":\"quoted-printable\"},{\"name\":\"MIME-Version\",\"value\":\"1.0\"},{\"name\":\"X-OriginatorOrg\",\"value\":\"uiowa.edu\"},{\"name\":\"X-MS-Exchange-CrossTenant-AuthAs\",\"value\":\"Internal\"},{\"name\":\"X-MS-Exchange-CrossTenant-AuthSource\",\"value\":\"BN6PR04MB0962.namprd04.prod.outlook.com\"},{\"name\":\"X-MS-Exchange-CrossTenant-Network-Message-Id\",\"value\":\"6ec767f9-50fe-47f8-f3f2-08d84edfcf64\"},{\"name\":\"X-MS-Exchange-CrossTenant-originalarrivaltime\",\"value\":\"02 Sep 2020 01:30:43.6328 (UTC)\"},{\"name\":\"X-MS-Exchange-CrossTenant-fromentityheader\",\"value\":\"Hosted\"},{\"name\":\"X-MS-Exchange-CrossTenant-id\",\"value\":\"1bc44595-9aba-4fc3-b8ec-7b94a5586fdc\"},{\"name\":\"X-MS-Exchange-CrossTenant-mailboxtype\",\"value\":\"HOSTED\"},{\"name\":\"X-MS-Exchange-CrossTenant-userprincipalname\",\"value\":\"bL8rIxZl0Sld3xLq4rMTj0vEP7WADWvl5tk2iCPL4YSID4PRlR8zvzmNO2cf7dk8dtcfLmTHpKvS3wOY9ihFdA==\"},{\"name\":\"X-MS-Exchange-Transport-CrossTenantHeadersStamped\",\"value\":\"BN6PR04MB1172\"}],\"commonHeaders\":{\"returnPath\":\"sender@example.com\",\"from\":[\"\\\"Sender\\\" \"],\"date\":\"Wed, 2 Sep 2020 01:30:43 +0000\",\"to\":[\"\\\"recipient@example.com\\\" \"],\"messageId\":\"<1344C740-07D3-476E-BEE7-6EB162294DF6@uiowa.edu>\",\"subject\":\"Test 500\"}},\"receipt\":{\"timestamp\":\"2020-09-02T01:30:50.233Z\",\"processingTimeMillis\":607,\"recipients\":[\"recipient@example.com\"],\"spamVerdict\":{\"status\":\"PASS\"},\"virusVerdict\":{\"status\":\"PASS\"},\"spfVerdict\":{\"status\":\"GRAY\"},\"dkimVerdict\":{\"status\":\"GRAY\"},\"dmarcVerdict\":{\"status\":\"FAIL\"},\"action\":{\"type\":\"S3\",\"topicArn\":\"arn:aws:sns:us-east-1:433802195282:yourapp-receipt-sns\",\"bucketName\":\"yourapp-uploads20200818192940697500000001\",\"objectKey\":\"17at0jiq08p0449huhf16qsmdi6sa1ltm069t801\"},\"dmarcPolicy\":\"none\"}}",
- "Timestamp": "2020-09-02T01:30:50.862Z",
- "SignatureVersion": "1",
- "Signature": "RNDPMv2Z5x09OECBbuuR3T4OiGuUpo4BdUVVaez5dFFiO3x29vA1D8QixUNl\n2K0sxEqgEe++GMNWSOgEfXF51fj6n0fD0xuol6FlcPN+ST/83+rKwe3KNajj\n+Voc1MPm5Htb328Lnhc3MFZyeM0YIgykqE75zAk0+3lAhk/4tnKsi0Cz7PIz\nq3mT6BwZbo9tRNBoniKg4hpEy4ePNLX3FZ9B4jFyaHXJ+KbpvEY0LYsIDbUA\nO4VP7+Q4gjfhKO4s1N+0KW5soBl/98ymgiBA4Yo9QBZeFwkQKItwdr/utuWA\noBdRkgpqv/Ac5/dIMTXT/K1SUkqMgxOEPWtk6RiI3A==\n",
- "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem",
- "UnsubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:012345678910:example-topic:abcdef01-abc1-abc1-abc1-abcdef123456"
-}
\ No newline at end of file
diff --git a/spec/fixtures/json/invalid_signature.json b/spec/fixtures/json/invalid_signature.json
deleted file mode 100644
index 7b9fb5bd..00000000
--- a/spec/fixtures/json/invalid_signature.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Type" : "SubscriptionConfirmation",
- "MessageId" : "abc12345-abc1-abc1-abc1-abc123456789",
- "Token" : "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1",
- "TopicArn" : "arn:aws:sns:eu-west-1:012345678910:example-topic",
- "Message" : "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:example-topic. To confirm the subscription, visit the SubscribeURL included in this message.",
- "SubscribeURL" : "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:example-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
- "Timestamp" : "2020-05-07T07:25:25.364Z",
- "SignatureVersion" : "1",
- "Signature" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==",
- "SigningCertURL" : "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem"
-}
diff --git a/spec/fixtures/json/recognized_topic_subscription_request.json b/spec/fixtures/json/recognized_topic_subscription_request.json
deleted file mode 100644
index a1ca6fb4..00000000
--- a/spec/fixtures/json/recognized_topic_subscription_request.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Type": "SubscriptionConfirmation",
- "MessageId": "abc12345-abc1-abc1-abc1-abc123456789",
- "Token": "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1",
- "TopicArn": "arn:aws:sns:eu-west-1:012345678910:recognized-topic",
- "Message": "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:recognized-topic. To confirm the subscription, visit the SubscribeURL included in this message.",
- "SubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:recognized-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
- "Timestamp": "2020-05-07T07:25:25.364Z",
- "SignatureVersion": "1",
- "Signature": "cjaRd4N8UcSsW7HszXfmAxECIJNcE1LDnUMocbksvw3naD7eGaK0adcRm54u\nzhypWoEUFSbxzysdo5JIzzgoSHV+1X/mmK45ToDCNrV2djfMUl301aslcM7g\n76lSCDlR7fH6d/V7OcCmxxW18VQfFCm0RR6/w1P/Ds1+++UDmt5OM57LrJ3x\nvxPLV6TfO/q2kBrQwQFXP8ewhieBnNJnlGmmMIOZi5vfepzTlxiniV8V/1zY\nxgmZfla3u7ugIG0PKLv+iTVCy4E/Z6bCUqPUY7d551iBTbaHP4YjhQ07P5NR\nrRSzlJYu52mBRtR5QAxSI7QItwt2EIVVcOI2npzM7g==\n",
- "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem"
-}
\ No newline at end of file
diff --git a/spec/fixtures/json/unrecognized_topic_subscription_request.json b/spec/fixtures/json/unrecognized_topic_subscription_request.json
deleted file mode 100644
index b5348a86..00000000
--- a/spec/fixtures/json/unrecognized_topic_subscription_request.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Type": "SubscriptionConfirmation",
- "MessageId": "abc12345-abc1-abc1-abc1-abc123456789",
- "Token": "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1",
- "TopicArn": "arn:aws:sns:eu-west-1:012345678910:unrecognized-topic",
- "Message": "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:unrecognized-topic. To confirm the subscription, visit the SubscribeURL included in this message.",
- "SubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:unrecognized-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
- "Timestamp": "2020-05-07T07:25:25.364Z",
- "SignatureVersion": "1",
- "Signature": "kxMQFU2DTFmvTrVWjPT6Op962Nad0a9oCv5iLqGL+sa2wb5DVGXdRwoo2IOo\nwGYvVGDkaI2sJxiMvdsOMc/2hQP+S1lDDvmDvs/QjM5ww8SdENrAYpBRfi5i\nYP7dupKyZ5XcpDOHoB++ORuq7Ydg7+AWrRnbEMn5mGYiHV+PGqQVzomNz5HO\ntNtxoO/bhIwPSPp+pPM/bX40U/jAR1xzVzmeAPwqCVseqcG9Mju0znA9nW0p\nVpKtAR6Be90mBbsm+6b5BzZyZsdYAmiqGP91MFP1r1tPb/gNNtfOcyWNT6pO\nwWq0a/+e+wp953ydLTJUKze4AkuTHzuhP7cPEPSKSQ==\n",
- "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem"
-}
\ No newline at end of file
diff --git a/spec/fixtures/json/valid_signature.json b/spec/fixtures/json/valid_signature.json
deleted file mode 100644
index 5dc99eae..00000000
--- a/spec/fixtures/json/valid_signature.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Type": "SubscriptionConfirmation",
- "MessageId": "abc12345-abc1-abc1-abc1-abc123456789",
- "Token": "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1",
- "TopicArn": "arn:aws:sns:eu-west-1:012345678910:example-topic",
- "Message": "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:example-topic. To confirm the subscription, visit the SubscribeURL included in this message.",
- "SubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:example-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
- "Timestamp": "2020-05-07T07:25:25.364Z",
- "SignatureVersion": "1",
- "Signature": "1a13u6m1qaBul+9lPdIX0E0c/qDaRSlFcTiETJnMizRoMS9YrKi/ZXYi/dVr\n4kaHt8c++dWoHgOiXm+AZrmYqyIUC5pjtJkHSowf4SkABQLuCDiEkl5lN5jx\niORunX/7Cuu7u0tgqfSIOtgiKUxSMttM+HvM0jeL67Osklu6cS/dxgPN5gv0\nKghMV/+aeCZ59YjBHhWlR3XXlVnlO2ttQ1UQI/PwrC3CRojla7jZX7s/Vjbu\nZFbdxzsR9iRaJJsVl0Glc9fAkvHbpX+7ulw1NuXToJyOwStEJqUIAmJXEbwA\nDANNncnQNpGJMbsCP7mSCZ5jNNZ7iF2E72sMN2zfDg==\n",
- "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem"
-}
\ No newline at end of file
diff --git a/spec/fixtures/pem/certificate.pem b/spec/fixtures/pem/certificate.pem
deleted file mode 100644
index 8a2debae..00000000
--- a/spec/fixtures/pem/certificate.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQjCCAiqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBLMRMwEQYKCZImiZPyLGQB
-GRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMRkwFwYDVQQDDBBSdWJ5
-IGNlcnRpZmljYXRlMB4XDTI0MDcxODEzNTYwMloXDTI1MDcxODEzNTYwMlowSzET
-MBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1YnktbGFuZzEZ
-MBcGA1UEAwwQUnVieSBjZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBANo4bPJC3wSyz08AdqQ+0wd61fyilOcSR0+5+ZKHCz//0hbk064F
-BEvQ1ir1AS2hprAAqKQoKX62OWdaJgtsp/fgmJmjG1XPT/MTc9Zdnn9MO5MrA94G
-IcnFhty8YI5/+HtSuVDQedtriZEQDTNorYhkX2zUX4zyv34RGEEYmwAJVPEApNMS
-1xFVjBBmcHZqHavsKFSDmdHK6m5bhk1V4sLqHPVeaOA9EuZm1TeKY9VxL3PoEJwv
-0hXEZKHxKQuGhzBGgsMQJnPsWnZJ0WPNM6/ka7Qfonp/U/CErXuPQl2XoHl85aSV
-0X0EIfSw8PKEB1IUJC6aAZDrrD8yNurR4M0CAwEAAaMxMC8wDgYDVR0PAQH/BAQD
-AgeAMB0GA1UdDgQWBBRp3PGg7ef7OHxvS/OcvR7aLl79KjANBgkqhkiG9w0BAQsF
-AAOCAQEArNP7O/WqYNm9si4JvBFNSqX6pI3JQ4KdmLLJZDb1tu5tBZEbZx/Dc3TX
-E8nfC0agNs15tgLRXDQPQ5UcLt/2Qy488gMiONFwAHbRWj6Sr/DagFXFzPpd+LEk
-/bgYsCuRqYy1tje72I5grLWFm/rt8uFhquAoaEuYPe3sJXdXxKq+yV0VqWPDKyBc
-tNKqAOrSUYfGAB4JQYBmRBMQnGlMEcZrvtDcLkAyRadI3RjLMfnBAflz/KyI5Dbc
-WUNsE4LjECSdznehnhhJyPvb/+CRWwMwde3EhZjgalC6POVM54DPOeDLk+v21hKN
-OKOpvfyLB+vnTma8CHpSVdSder8tmA==
------END CERTIFICATE-----
diff --git a/spec/fixtures/pem/privatekey.pem b/spec/fixtures/pem/privatekey.pem
deleted file mode 100644
index 193ff0cc..00000000
--- a/spec/fixtures/pem/privatekey.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEA2jhs8kLfBLLPTwB2pD7TB3rV/KKU5xJHT7n5kocLP//SFuTT
-rgUES9DWKvUBLaGmsACopCgpfrY5Z1omC2yn9+CYmaMbVc9P8xNz1l2ef0w7kysD
-3gYhycWG3Lxgjn/4e1K5UNB522uJkRANM2itiGRfbNRfjPK/fhEYQRibAAlU8QCk
-0xLXEVWMEGZwdmodq+woVIOZ0crqbluGTVXiwuoc9V5o4D0S5mbVN4pj1XEvc+gQ
-nC/SFcRkofEpC4aHMEaCwxAmc+xadknRY80zr+RrtB+ien9T8ISte49CXZegeXzl
-pJXRfQQh9LDw8oQHUhQkLpoBkOusPzI26tHgzQIDAQABAoIBAE5RjABSsbn89txS
-vUHrbk+z7VLzgt9/tupNQ94r64S3qs4eqD4/fLA9LnBSaG7ZInrucZgg9euNOQL3
-3smg4JPdHsedO3VLp1UFOUDJbtYfJQ6HlKa9qqjA5MsaLMlX8nVIVkxD1khCyyeu
-DB7URdu6smjbu8NZaBK1ze+nBhI3nP+Dr5tM6XCvHMu6D7BMgTBIPf/+ODlXXuDC
-Sj+VE6IIbLYGgma6X1hl4mllg2yt6fjhE2WobMsfUOVAoqPcxEehmVXn44nNIVQM
-sG0qHJH+SGnOZux+05IVD5lXE/onSd+njtGpyTjSgZQmZkx+fJuQw4BVfNuzNQJ8
-4jyJ1OECgYEA/6dmP2C27BDGxkz9pH9pkgxPzjHZcFd0AT7HT1oWxUrhZO6C83Lt
-/xiGF4qFH22yPXFkbkitxIZdXcwI4EAAeoPPdmEasIvvbChlDpnoWcgELVzShRSx
-321Qxh4VdLBQrSlOqtJvEduY8U7/75EEDSCdidoDgW263J1X6kuQ/RUCgYEA2oQN
-lET06mhwPOwCATc/ZQJ/QaIaDpPjbi+DB2ZcptKIcbCv5Y+maK3mBYzOGUUyXKcG
-EEn/V+m3PaQChAUNK+Uuq700+WBHxynxpGnOG1PjqBlMNuOL/6n/N+QD3LR6uY2S
-aSxJAFx+dgZfjm0l4+cGOdf6dMMCTq7nV1lYctkCgYEAj56qKTaa7JksIeDEqTHO
-y/ZQqwSEI8FtcPmknGZ+3k0HvFzlggBxxVowkm8GBDbq5+uYwP/hZsMZFoV2AwzR
-eAIufVFl3gJu+XLj+sTpq+5asmUv+wU6O8s8kl/6K7iVSgInqH1ZWk3kaMO5sgrk
-nL9S4UtxprdPP3rBFeVnyVUCgYBZOjz1Q2ci5LyYE+MJrg6j524hVdkABOGEl8AQ
-YHsK38M5cWWR/qN78S6RK5ro9LmI3eb69cxfkJ7ze6pPUGS9fNse46bjAa6to/H5
-Kf8wZ4P5m0Lk0uvS3Q7LOr9c+xF1/VpAugWhMSOufBG+7dDgC/Ed45Rw40Ro7sCm
-iWQ1mQKBgQD4eIVgi6ae9rfND52TAMidzzEShWFB6ruoVSCDHjY5pinwy1qQpDGl
-qz/4WfOp7+HOcPed95EhfNIKvW71oUBgrmcCFfZ7vEmmUCRbk9D563SHkCri3Vjk
-FAOgPBSOQyeZxHDUIQifV3dP/0YxgAjlzyDCI8Pbj62T0FtpY3hLcw==
------END RSA PRIVATE KEY-----
\ No newline at end of file
diff --git a/spec/fixtures/txt/s3_email.txt b/spec/fixtures/txt/s3_email.txt
deleted file mode 100644
index 0e1ace70..00000000
--- a/spec/fixtures/txt/s3_email.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-Return-Path:
-Received: from example.com (example.com [127.0.0.1])
- by inbound-smtp.us-east-1.amazonaws.com with SMTP id 17at0jiq08p0449huhf16qsmdi6sa1ltm069t801
- for test@test.example.com;
- Wed, 02 Sep 2020 01:30:50 +0000 (UTC)
-X-SES-Spam-Verdict: PASS
-X-SES-Virus-Verdict: PASS
-X-SES-RECEIPT: AEFBQUFBQUFBQUFHMWlxem9Gb1ZOemNkamlTeFlYdlZUSmUwVVZhYndjK213dHFIM0dVRTYwUlk1UlpBQVVVTXhQRUd1MTN6YTFJalp0TFdMZjhOOUZGSlJCYkxEV2craXhpOG02d2xDc2FtY2dNdVMvRE9QWWpNVkxBWVZzMyt5MHBTUXV5KzM5aDY1Vng5UnZsZTdTK2dGVDF5RVc1QndOd0xvbndNRlR3TDZjd2cxT2c2UVFQbVN2andMS09VM2R5elFrTGk3RnF0WXI3WDZ1alhkUzJxdzhzU1dwT3FPZEFsU0VNc3RpTWM0QStFZDB5RFd5SnpRelBJWnJjelZPRytudEVpNTc5dVZRUXMra2lrby9wOExhR3JqTi9xNkZnNHREN3BmSmVYS25Jeis2NDRyaEE9PQ==
-X-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=WGBoUguIq9047YXpCaubVCtm/ISR3JEVkvm/yAfL2MrAryQcYsTdUM6zzStPyvOm0QsonOKsWJ0O2YyuQDX1dvBmggdeUqZq08laD+Xuy1L6ODm0O/EQE9wDitj0KqXxOgMr3oM7tpcTTGLcCgXERFZbmI+1ACeeA7fbylMasIM=; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1599010250; v=1; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;
-From: "Smith, Bob E"
-To: "test@test.example.com"
-
-Subject: Test 500
-Thread-Topic: Test 500
-Thread-Index: AQHWgMisvDz2gn/lKEK/giPayBxk7g==
-Date: Wed, 2 Sep 2020 01:30:43 +0000
-Message-ID: <1344C740-07D3-476E-BEE7-6EB162294DF6@example.com>
-Accept-Language: en-US
-Content-Language: en-US
-Content-Type: text/plain; charset="us-ascii"
-Content-ID:
-Content-Transfer-Encoding: quoted-printable
-MIME-Version: 1.0
-
-Aaaron
diff --git a/spec/test_helper.rb b/spec/test_helper.rb
index 920ed2c6..5a731e20 100644
--- a/spec/test_helper.rb
+++ b/spec/test_helper.rb
@@ -3,24 +3,4 @@
ENV['RAILS_ENV'] = 'test'
require_relative 'dummy/config/environment'
-require 'webmock/rspec'
require 'rspec/rails'
-
-ActiveRecord::Migration.maintain_test_schema!
-
-class TestMailer < ActionMailer::Base
- layout nil
-
- def deliverable(options = {})
- headers(options.delete(:headers))
- mail(options)
- end
-end
-
-def fixture_for(name, type:)
- File.read(File.join('spec', 'fixtures', type.to_s, "#{name}.#{type}"))
-end
-
-RSpec.configure do |config|
- config.use_transactional_fixtures = true
-end
diff --git a/tasks/fixtures.rake b/tasks/fixtures.rake
deleted file mode 100644
index e183ce21..00000000
--- a/tasks/fixtures.rake
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-require 'openssl'
-require 'json'
-require 'base64'
-
-PRIVATE_KEY = 'spec/fixtures/pem/privatekey.pem'
-CERTIFICATE = 'spec/fixtures/pem/certificate.pem'
-AWS_FIXTURES = FileList['spec/fixtures/json/*.json'].exclude('**/*/invalid_signature.json')
-SIGNABLE_KEYS = %w[
- Message
- MessageId
- Subject
- SubscribeURL
- Timestamp
- Token
- TopicArn
- Type
-].freeze
-
-file PRIVATE_KEY do |t|
- key = OpenSSL::PKey::RSA.new 2048
- File.write(t.name, key.to_pem)
-end
-
-file CERTIFICATE => PRIVATE_KEY do |t|
- key = OpenSSL::PKey::RSA.new File.read(PRIVATE_KEY)
- cert = OpenSSL::X509::Certificate.new
- cert.version = 2
- cert.serial = 2
- cert.subject = OpenSSL::X509::Name.parse '/DC=org/DC=ruby-lang/CN=Ruby certificate'
- cert.issuer = cert.subject # root CA is the issuer
- cert.public_key = key.public_key
- cert.not_before = Time.now
- cert.not_after = cert.not_before + (1 * 365 * 24 * 60 * 60) # 10 years validity
- ef = OpenSSL::X509::ExtensionFactory.new
- ef.subject_certificate = cert
- ef.issuer_certificate = cert
- cert.add_extension(ef.create_extension('keyUsage', 'digitalSignature', true))
- cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
- cert.sign(key, OpenSSL::Digest.new('SHA256'))
-
- File.write(t.name, cert.to_pem)
-end
-task certificates: [PRIVATE_KEY, CERTIFICATE]
-
-desc 'Sign AWS SES fixtures, must be called if fixtures are modified.'
-task sign_aws_fixtures: :certificates do
- def canonical_string(message)
- parts = []
-
- SIGNABLE_KEYS.each do |key|
- value = message[key]
- parts << "#{key}\n#{value}\n" unless value.nil? || value.empty?
- end
- parts.join
- end
-
- key = OpenSSL::PKey::RSA.new File.read(PRIVATE_KEY)
-
- AWS_FIXTURES.each do |fixture|
- data = JSON.parse File.read(fixture)
- string = canonical_string(data)
- signed_string = key.sign('SHA1', string)
- data['Signature'] = Base64.encode64(signed_string)
- File.write(fixture, JSON.pretty_generate(data))
- end
-end