outbound_mailbox 1.0.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/MIT-LICENSE +19 -0
- data/README.md +86 -0
- data/Rakefile +14 -0
- data/app/controllers/rails/conductor/outbound_mailbox/outbound_emails_controller.rb +25 -0
- data/app/models/outbound_mailbox/outbound_email.rb +50 -0
- data/app/models/outbound_mailbox/record.rb +7 -0
- data/app/views/layouts/outbound_mailbox/conductor.html.erb +8 -0
- data/app/views/rails/conductor/outbound_mailbox/outbound_emails/index.html.erb +24 -0
- data/app/views/rails/conductor/outbound_mailbox/outbound_emails/show.html.erb +19 -0
- data/config/routes.rb +9 -0
- data/lib/generators/outbound_mailbox/install_generator.rb +17 -0
- data/lib/generators/outbound_mailbox/templates/migration.rb +13 -0
- data/lib/outbound_mailbox/engine.rb +28 -0
- data/lib/outbound_mailbox/mail_delivery.rb +17 -0
- data/lib/outbound_mailbox/version.rb +5 -0
- data/lib/outbound_mailbox.rb +46 -0
- metadata +154 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 2593221e73c6c30a39d3bf5823ab1daff84827965f17352ef4970ff44ad6609b
|
|
4
|
+
data.tar.gz: f2b88374df3d4e60c348ea100b56a09aa284764af41d1854588ee29a7062e6ec
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fd2758390597ed5b28ddb4508fcddab6b7814b099e901c04dd053f88583765784952d7de9c241c821b38cee03b6b0bc1dc83f1111c5bbdb6b8fcd0c84a5ff240
|
|
7
|
+
data.tar.gz: '04084ae34c19dfafcd23691c8fe8ade5611ec8eab93e10d8c97c436b13d34bda1be67be7af5ccad87afd514f390fa7111a2e3393421ae24b681dc45782c1f6b1'
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) Ackama
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Outbound Mailbox
|
|
2
|
+
|
|
3
|
+
Rails engine that stores **outbound** email the same way [Action Mailbox](https://guides.rubyonrails.org/action_mailbox_basics.html) stores **inbound** email: Active Record metadata, raw RFC822 source in Active Storage, a Mail delivery method, and an HTML conductor at `/rails/conductor/outbound_mailbox/outbound_emails` when enabled — by default if Action Mailer uses `delivery_method :outbound_mailbox`, or any time via `config.outbound_mailbox.mount_conductor`.
|
|
4
|
+
|
|
5
|
+
There is **no runtime dependency on Action Mailer** in the library; the delivery class implements Mail’s delivery contract so any stack that ends in `Mail::Message#deliver!` can use it. Typical Rails hosts configure Action Mailer to use this method in development.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add to your `Gemfile`:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem "outbound_mailbox"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle install
|
|
19
|
+
bin/rails generate outbound_mailbox:install
|
|
20
|
+
bin/rails db:migrate
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Optional: use a dedicated Active Storage service for captured mail (mirrors Action Mailbox’s `config.action_mailbox.storage_service`):
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
# config/application.rb
|
|
27
|
+
config.outbound_mailbox.storage_service = :local # or any configured service name
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
To browse captured mail via the conductor without using Action Mailer's `:outbound_mailbox` delivery method (for example you call `OutboundMailbox::OutboundEmail.create_from_mail!` yourself or use a custom delivery path), enable routes explicitly:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
# config/application.rb
|
|
34
|
+
config.outbound_mailbox.mount_conductor = true
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Set to `false` to hide the conductor even when `delivery_method` is `:outbound_mailbox`. You can also assign a proc: `config.outbound_mailbox.mount_conductor = ->(app) { ... }` (must return a boolean-coercible value). The default is `nil`, meaning mount when `config.action_mailer.delivery_method` is `:outbound_mailbox`.
|
|
38
|
+
|
|
39
|
+
## Capturing mail in development
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
# config/environments/development.rb
|
|
43
|
+
config.action_mailer.delivery_method = :outbound_mailbox
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This replaces real SMTP delivery in that environment (similar to `:test` or Letter Opener). Plain `Mail` is also supported if you assign the same delivery class.
|
|
47
|
+
|
|
48
|
+
## Conductor
|
|
49
|
+
|
|
50
|
+
By default, when `config.action_mailer.delivery_method` is **`:outbound_mailbox`**, the engine registers conductor routes under:
|
|
51
|
+
|
|
52
|
+
`/rails/conductor/outbound_mailbox/outbound_emails`
|
|
53
|
+
|
|
54
|
+
You can override that with `config.outbound_mailbox.mount_conductor`; see **Installation** optional settings above.
|
|
55
|
+
|
|
56
|
+
List and show stored messages, or **Incinerate** to delete a record and purge its blob. When routes are not registered, those URLs are not routed (**404**). Route registration follows `config/routes.rb` (startup and reload in development).
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Testing this gem
|
|
60
|
+
|
|
61
|
+
Tests boot a **single-file** Rails app in [`test/dummy/app.rb`](test/dummy/app.rb). Migrations live under [`test/dummy/db/migrate`](test/dummy/db/migrate).
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bundle install
|
|
65
|
+
bundle exec rake test
|
|
66
|
+
bundle exec rubocop
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Continuous integration uses the **latest stable MRI Ruby** [`ruby/setup-ruby`](https://github.com/ruby/setup-ruby), `ruby-version: "ruby"` and exercises **Rails 8.1** (default `Gemfile`), **Rails 8.0**, **Rails 7.1**, and **Rails 7.0** via [`gemfiles/rails_8_1.gemfile`](gemfiles/rails_8_1.gemfile), [`gemfiles/rails_8_0.gemfile`](gemfiles/rails_8_0.gemfile), [`gemfiles/rails_7_1.gemfile`](gemfiles/rails_7_1.gemfile), and [`gemfiles/rails_7_0.gemfile`](gemfiles/rails_7_0.gemfile). To match a matrix entry locally:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle install
|
|
73
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle exec rake test
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The gem’s **Gemfile** includes `actionmailer` so `config.action_mailer` exists in that app; the **gemspec** does not list `action_mailer` or `actionmailbox` as runtime dependencies. Runtime Rails components are constrained to **`>= 7.0`, `< 8.2`** (`actionpack`, `activestorage`, `activerecord`, `railties`). The gem requires **Ruby 3.1+** (`required_ruby_version`).
|
|
77
|
+
|
|
78
|
+
## Releasing
|
|
79
|
+
|
|
80
|
+
Releases are done automatically by GitHub Actions when a new tag is pushed to the repository.
|
|
81
|
+
|
|
82
|
+
To release a new version, create a pull request updating the "Unreleased" section of `CHANGELOG.md` file to reflect the upcoming version and expected release date, and to update the version number in `lib/outbound_mailbox/version.rb`. Once the pull request is merged, create a new tag in the format `vX.Y.Z`, which will trigger GitHub Actions to publish the new version to RubyGems.
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT — see [MIT-LICENSE](MIT-LICENSE).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "bundler/setup"
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
|
|
5
|
+
require "rake/testtask"
|
|
6
|
+
|
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
|
8
|
+
t.libs << "test"
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
10
|
+
t.verbose = true
|
|
11
|
+
t.warning = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
task default: :test
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Conductor
|
|
5
|
+
module OutboundMailbox
|
|
6
|
+
class OutboundEmailsController < ActionController::Base
|
|
7
|
+
layout "outbound_mailbox/conductor"
|
|
8
|
+
|
|
9
|
+
def index
|
|
10
|
+
@outbound_emails = ::OutboundMailbox::OutboundEmail.order(created_at: :desc)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def show
|
|
14
|
+
@outbound_email = ::OutboundMailbox::OutboundEmail.find(params[:id])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def destroy
|
|
18
|
+
@outbound_email = ::OutboundMailbox::OutboundEmail.find(params[:id])
|
|
19
|
+
@outbound_email.incinerate
|
|
20
|
+
redirect_to rails_conductor_outbound_mailbox_outbound_emails_path, notice: "Email incinerated"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mail"
|
|
4
|
+
require "openssl"
|
|
5
|
+
require "stringio"
|
|
6
|
+
|
|
7
|
+
module OutboundMailbox
|
|
8
|
+
# Persists the raw RFC822 source in Active Storage (metadata is a checksum only; outbound mail does not need RFC Message-ID for deduplication).
|
|
9
|
+
class OutboundEmail < Record
|
|
10
|
+
has_one_attached :raw_email
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def create_from_mail!(mail)
|
|
14
|
+
source = mail.encoded
|
|
15
|
+
checksum = OpenSSL::Digest::SHA1.hexdigest(source)
|
|
16
|
+
create!(
|
|
17
|
+
raw_email: create_and_upload_raw_blob!(source),
|
|
18
|
+
message_checksum: checksum
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def create_and_upload_raw_blob!(source)
|
|
25
|
+
args = {
|
|
26
|
+
io: StringIO.new(source),
|
|
27
|
+
filename: "message.eml",
|
|
28
|
+
content_type: "message/rfc822"
|
|
29
|
+
}
|
|
30
|
+
args[:service_name] = OutboundMailbox.storage_service if OutboundMailbox.storage_service.present?
|
|
31
|
+
ActiveStorage::Blob.create_and_upload!(**args)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def mail
|
|
36
|
+
@mail ||= OutboundMailbox.mail_message_from_raw_source(source)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def source
|
|
40
|
+
@source ||= raw_email.download
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def incinerate
|
|
44
|
+
transaction do
|
|
45
|
+
raw_email.purge if raw_email.attached?
|
|
46
|
+
destroy!
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<h1>Outbound emails</h1>
|
|
2
|
+
|
|
3
|
+
<table>
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<th>ID</th>
|
|
7
|
+
<th>Subject</th>
|
|
8
|
+
<th>Checksum</th>
|
|
9
|
+
<th>Created</th>
|
|
10
|
+
<th></th>
|
|
11
|
+
</tr>
|
|
12
|
+
</thead>
|
|
13
|
+
<tbody>
|
|
14
|
+
<% @outbound_emails.each do |email| %>
|
|
15
|
+
<tr>
|
|
16
|
+
<td><%= email.id %></td>
|
|
17
|
+
<td><%= email.mail.subject %></td>
|
|
18
|
+
<td><code><%= email.message_checksum.slice(0, 12) %>…</code></td>
|
|
19
|
+
<td><%= email.created_at %></td>
|
|
20
|
+
<td><%= link_to "Show", rails_conductor_outbound_mailbox_outbound_email_path(email) %></td>
|
|
21
|
+
</tr>
|
|
22
|
+
<% end %>
|
|
23
|
+
</tbody>
|
|
24
|
+
</table>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<h1>Outbound email #<%= @outbound_email.id %></h1>
|
|
2
|
+
|
|
3
|
+
<dl>
|
|
4
|
+
<dt>Checksum</dt>
|
|
5
|
+
<dd><code><%= @outbound_email.message_checksum %></code></dd>
|
|
6
|
+
<dt>Created</dt>
|
|
7
|
+
<dd><%= @outbound_email.created_at %></dd>
|
|
8
|
+
</dl>
|
|
9
|
+
|
|
10
|
+
<h2>Headers</h2>
|
|
11
|
+
<pre><%= ERB::Util.html_escape(@outbound_email.mail.header.fields.map(&:to_s).join("\n")) %></pre>
|
|
12
|
+
|
|
13
|
+
<h2>Raw source</h2>
|
|
14
|
+
<pre><%= ERB::Util.html_escape(@outbound_email.source) %></pre>
|
|
15
|
+
|
|
16
|
+
<p>
|
|
17
|
+
<%= link_to "Back to list", rails_conductor_outbound_mailbox_outbound_emails_path %>
|
|
18
|
+
<%= button_to "Incinerate", rails_conductor_outbound_mailbox_outbound_email_path(@outbound_email), method: :delete, form: { data: { turbo: false } } %>
|
|
19
|
+
</p>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Rails.application.routes.draw do
|
|
4
|
+
if OutboundMailbox.mount_conductor_routes?(Rails.application)
|
|
5
|
+
scope "rails/conductor/outbound_mailbox/", module: "rails/conductor/outbound_mailbox" do
|
|
6
|
+
resources :outbound_emails, only: %i[index show destroy], as: :rails_conductor_outbound_mailbox_outbound_emails
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/active_record/migration"
|
|
5
|
+
|
|
6
|
+
module OutboundMailbox
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
include ActiveRecord::Generators::Migration
|
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
|
+
|
|
11
|
+
desc "Creates an Outbound Mailbox migration."
|
|
12
|
+
|
|
13
|
+
def copy_migration
|
|
14
|
+
migration_template "migration.rb", "db/migrate/create_outbound_mailbox_outbound_emails.rb"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateOutboundMailboxOutboundEmails < ActiveRecord::Migration::Current
|
|
4
|
+
def change
|
|
5
|
+
create_table :outbound_mailbox_outbound_emails do |t|
|
|
6
|
+
t.string :message_checksum, null: false
|
|
7
|
+
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :outbound_mailbox_outbound_emails, :created_at
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OutboundMailbox
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace OutboundMailbox
|
|
6
|
+
|
|
7
|
+
config.generators do |g|
|
|
8
|
+
g.test_framework :test_unit
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
config.outbound_mailbox = ActiveSupport::OrderedOptions.new
|
|
12
|
+
config.outbound_mailbox.storage_service = nil
|
|
13
|
+
# nil = derive from Action Mailer delivery_method (see OutboundMailbox.mount_conductor_routes?)
|
|
14
|
+
config.outbound_mailbox.mount_conductor = nil
|
|
15
|
+
|
|
16
|
+
initializer "outbound_mailbox.storage_service" do
|
|
17
|
+
config.after_initialize do |app|
|
|
18
|
+
OutboundMailbox.storage_service = app.config.outbound_mailbox.storage_service
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
initializer "outbound_mailbox.action_mailer" do
|
|
23
|
+
ActiveSupport.on_load(:action_mailer) do
|
|
24
|
+
ActionMailer::Base.add_delivery_method :outbound_mailbox, OutboundMailbox::MailDelivery
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OutboundMailbox
|
|
4
|
+
# Mail delivery handler (same contract as Mail::TestMailer).
|
|
5
|
+
# Register with Action Mailer via +config.action_mailer.delivery_method = :outbound_mailbox+.
|
|
6
|
+
class MailDelivery
|
|
7
|
+
attr_accessor :settings
|
|
8
|
+
|
|
9
|
+
def initialize(values = {})
|
|
10
|
+
@settings = (values || {}).dup
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def deliver!(mail)
|
|
14
|
+
OutboundMailbox::OutboundEmail.create_from_mail!(mail)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mail"
|
|
4
|
+
require "outbound_mailbox/version"
|
|
5
|
+
require "outbound_mailbox/engine"
|
|
6
|
+
require "outbound_mailbox/mail_delivery"
|
|
7
|
+
|
|
8
|
+
module OutboundMailbox
|
|
9
|
+
mattr_accessor :storage_service, default: nil
|
|
10
|
+
|
|
11
|
+
# True when +delivery_method+ is configured as +outbound_mailbox+ for Action Mailer.
|
|
12
|
+
# See also {.mount_conductor_routes?} for overriding via +config.outbound_mailbox.mount_conductor+.
|
|
13
|
+
def self.conductor_routes_enabled_for_delivery_method?(delivery_method)
|
|
14
|
+
delivery_method&.to_sym == :outbound_mailbox
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Whether conductor routes should be drawn (+config/routes.rb+).
|
|
18
|
+
#
|
|
19
|
+
# +config.outbound_mailbox.mount_conductor+ must be one of:
|
|
20
|
+
# * +nil+ (default) — mount only when {.conductor_routes_enabled_for_delivery_method?}
|
|
21
|
+
# is true for +app.config.action_mailer.delivery_method+.
|
|
22
|
+
# * +true+ / +false+ — force conductor routes on or off (ignore delivery method). Use +true+
|
|
23
|
+
# if you persist mail without setting Action Mailer to +:outbound_mailbox+ but still want the UI.
|
|
24
|
+
# * Anything responding to +call+ (+Proc+, method object, ...) — invoked as +callable.call(app)+;
|
|
25
|
+
# the return value is coerced with +!!+ so use a boolean return for clarity.
|
|
26
|
+
def self.mount_conductor_routes?(app)
|
|
27
|
+
raw = app.config.outbound_mailbox.mount_conductor
|
|
28
|
+
case raw
|
|
29
|
+
when nil
|
|
30
|
+
conductor_routes_enabled_for_delivery_method?(app.config.action_mailer.delivery_method)
|
|
31
|
+
when true, false
|
|
32
|
+
raw
|
|
33
|
+
else
|
|
34
|
+
unless raw.respond_to?(:call)
|
|
35
|
+
raise ArgumentError, "config.outbound_mailbox.mount_conductor must be nil, true/false, or callable; got #{raw.class}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
!!raw.call(app)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Same behavior as Action Mailbox’s +Mail.from_source+, without pulling in that gem.
|
|
43
|
+
def self.mail_message_from_raw_source(source)
|
|
44
|
+
Mail.new(Mail::Utilities.binary_unsafe_to_crlf(source.to_s))
|
|
45
|
+
end
|
|
46
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: outbound_mailbox
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ackama
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: actionpack
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '8.2'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '7.0'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '8.2'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: activestorage
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '7.0'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '8.2'
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '7.0'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '8.2'
|
|
52
|
+
- !ruby/object:Gem::Dependency
|
|
53
|
+
name: activerecord
|
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '7.0'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '8.2'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '7.0'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '8.2'
|
|
72
|
+
- !ruby/object:Gem::Dependency
|
|
73
|
+
name: mail
|
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: 2.8.0
|
|
79
|
+
type: :runtime
|
|
80
|
+
prerelease: false
|
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: 2.8.0
|
|
86
|
+
- !ruby/object:Gem::Dependency
|
|
87
|
+
name: railties
|
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '7.0'
|
|
93
|
+
- - "<"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '8.2'
|
|
96
|
+
type: :runtime
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '7.0'
|
|
103
|
+
- - "<"
|
|
104
|
+
- !ruby/object:Gem::Version
|
|
105
|
+
version: '8.2'
|
|
106
|
+
description: Rails engine that stores outbound mail like Action Mailbox stores inbound
|
|
107
|
+
mail.
|
|
108
|
+
email:
|
|
109
|
+
- hello@ackama.com
|
|
110
|
+
executables: []
|
|
111
|
+
extensions: []
|
|
112
|
+
extra_rdoc_files: []
|
|
113
|
+
files:
|
|
114
|
+
- MIT-LICENSE
|
|
115
|
+
- README.md
|
|
116
|
+
- Rakefile
|
|
117
|
+
- app/controllers/rails/conductor/outbound_mailbox/outbound_emails_controller.rb
|
|
118
|
+
- app/models/outbound_mailbox/outbound_email.rb
|
|
119
|
+
- app/models/outbound_mailbox/record.rb
|
|
120
|
+
- app/views/layouts/outbound_mailbox/conductor.html.erb
|
|
121
|
+
- app/views/rails/conductor/outbound_mailbox/outbound_emails/index.html.erb
|
|
122
|
+
- app/views/rails/conductor/outbound_mailbox/outbound_emails/show.html.erb
|
|
123
|
+
- config/routes.rb
|
|
124
|
+
- lib/generators/outbound_mailbox/install_generator.rb
|
|
125
|
+
- lib/generators/outbound_mailbox/templates/migration.rb
|
|
126
|
+
- lib/outbound_mailbox.rb
|
|
127
|
+
- lib/outbound_mailbox/engine.rb
|
|
128
|
+
- lib/outbound_mailbox/mail_delivery.rb
|
|
129
|
+
- lib/outbound_mailbox/version.rb
|
|
130
|
+
homepage: https://github.com/ackama/outbound_mailbox
|
|
131
|
+
licenses:
|
|
132
|
+
- MIT
|
|
133
|
+
metadata:
|
|
134
|
+
homepage_uri: https://github.com/ackama/outbound_mailbox
|
|
135
|
+
source_code_uri: https://github.com/ackama/outbound_mailbox
|
|
136
|
+
rdoc_options: []
|
|
137
|
+
require_paths:
|
|
138
|
+
- lib
|
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: 3.1.0
|
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
|
+
requirements:
|
|
146
|
+
- - ">="
|
|
147
|
+
- !ruby/object:Gem::Version
|
|
148
|
+
version: '0'
|
|
149
|
+
requirements: []
|
|
150
|
+
rubygems_version: 3.6.9
|
|
151
|
+
specification_version: 4
|
|
152
|
+
summary: Rails engine that stores outbound mail like Action Mailbox stores inbound
|
|
153
|
+
mail.
|
|
154
|
+
test_files: []
|