mailbox-kit 0.1.0 → 0.1.1
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 +4 -4
- data/README.md +12 -31
- data/docs/integration.md +13 -62
- data/lib/mailbox_kit/active_record/base.rb +24 -5
- data/lib/mailbox_kit/inbound_email.rb +78 -15
- data/lib/mailbox_kit/mailboxes/service.rb +19 -8
- data/lib/mailbox_kit/version.rb +1 -1
- metadata +1 -2
- data/docs/upgrading.md +0 -60
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b8650dea4b54dbd598376075edb422437abd1f64fb88aaae1b1d342f0bdd35d
|
|
4
|
+
data.tar.gz: 96f6170e145f22e14469cec036bdd4858ed10c2f518429fa72ef866fe197a345
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f29ae48e734ffbdfb5ef3074188c9189eb666eecc84644094439c698efe507753d0af829b41f2df7b7ee399f1cec50ed164bfc4e236bcfe484e02cac847948a
|
|
7
|
+
data.tar.gz: fbb0c980266f89fa4e96550de66982afa323a8958d3cfce1c4b950d0248385dc07144f0d52c16c98355f35ee367479add6de70351766e179a33100698dcf4043
|
data/README.md
CHANGED
|
@@ -7,22 +7,14 @@ and access control. SQLite works out of the box; database tenancy is opt-in.
|
|
|
7
7
|
Rails already stores raw email, parses it, routes it to handlers, and runs
|
|
8
8
|
processing jobs. Mailbox Kit adds the inbox your users interact with.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Install
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
It includes this core; use the Cloudflare installer.
|
|
14
|
-
- **An existing Action Mailbox integration:** install this core and attach received
|
|
15
|
-
email to inboxes. Follow the example below.
|
|
16
|
-
- **Only processing incoming email:** Action Mailbox alone may be enough.
|
|
17
|
-
|
|
18
|
-
Add Mailbox Kit 0.1 to your Gemfile:
|
|
12
|
+
For a Rails app using another inbound provider:
|
|
19
13
|
|
|
20
14
|
```ruby
|
|
21
15
|
gem "mailbox-kit", "~> 0.1.0"
|
|
22
16
|
```
|
|
23
17
|
|
|
24
|
-
For a new Rails 7.2–8.1 application:
|
|
25
|
-
|
|
26
18
|
```sh
|
|
27
19
|
bundle install
|
|
28
20
|
bin/rails action_mailbox:install
|
|
@@ -30,8 +22,10 @@ bin/rails generate mailbox_kit:install
|
|
|
30
22
|
bin/rails db:migrate
|
|
31
23
|
```
|
|
32
24
|
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
Skip `action_mailbox:install` if Action Mailbox is already configured.
|
|
26
|
+
|
|
27
|
+
For Cloudflare, use the [Cloudflare mailbox guide](https://github.com/cole-robertson/cloudflare-email/blob/main/docs/mailboxes.md)
|
|
28
|
+
instead. Cloudflare Email installs Mailbox Kit automatically.
|
|
35
29
|
|
|
36
30
|
## Create an inbox in code
|
|
37
31
|
|
|
@@ -81,24 +75,11 @@ The optional management engine provides a server-rendered UI with no frontend
|
|
|
81
75
|
build. Your application supplies authentication and authorizes each action;
|
|
82
76
|
access is denied until configured. See [management setup](docs/integration.md#management-interface).
|
|
83
77
|
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
| Layer | Owns |
|
|
87
|
-
| --- | --- |
|
|
88
|
-
| Rails | Raw MIME, Active Storage, parsing, routing, processing jobs/status, cleanup policy, Action Mailer |
|
|
89
|
-
| Mailbox Kit | Inbox identities, addresses/aliases, memberships, read/archive state, selective retention, optional tenant context, management UI |
|
|
90
|
-
| Cloudflare | Request verification, authoritative envelope metadata, Worker retries/storage, sending, delivery feedback, provisioning |
|
|
91
|
-
| Your app | Users/organizations/sites, ownership lifecycle, authorization, sender acceptance, business effects |
|
|
92
|
-
|
|
93
|
-
Inbound and outbound can use different providers through Rails. The core does
|
|
94
|
-
not send email or supply a universal outbound adapter registry. `owner_ref` is an
|
|
95
|
-
application-managed reference; it is not an automatic `has_mailbox` association
|
|
96
|
-
or permission grant.
|
|
78
|
+
## More features
|
|
97
79
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Raw storage and processing remain Rails responsibilities.
|
|
80
|
+
Use the [integration guide](docs/integration.md) for aliases, catch-all addresses,
|
|
81
|
+
retention, authentication, and separate tenant databases.
|
|
101
82
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
83
|
+
Your app supplies users, organizations, sender policy, and mailbox permissions.
|
|
84
|
+
`owner_ref` stores your reference to an application record; it does not grant access.
|
|
85
|
+
Inbound and outbound email can use different providers through Rails.
|
data/docs/integration.md
CHANGED
|
@@ -6,29 +6,9 @@ configurable retention. Mailbox Kit adds inbox identities, addresses/aliases,
|
|
|
6
6
|
membership, read/archive state, scoped access and a server-rendered management UI.
|
|
7
7
|
SQLite works; separate tenant databases are opt-in.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
can use `gem "mailbox-kit", "~> 0.1"`.
|
|
13
|
-
|
|
14
|
-
## What belongs where?
|
|
15
|
-
|
|
16
|
-
| Layer | Responsibility |
|
|
17
|
-
| --- | --- |
|
|
18
|
-
| Mailbox Kit | Inbox identities, addresses, recipient lookup, membership, read/archive/purge, selective retention, tenant context, management UI |
|
|
19
|
-
| Rails | InboundEmail records, original MIME/ActiveStorage, parsing, processing callbacks/status, routing jobs, configurable retention, and ActionMailer |
|
|
20
|
-
| Provider integration | Verify incoming requests and envelope recipients, deliver outgoing messages, authenticate delivery feedback, configure DNS/routes |
|
|
21
|
-
| Your application | Users, organizations, sites, permissions, sender acceptance and business workflows |
|
|
22
|
-
|
|
23
|
-
Mailbox Kit does not require Cloudflare, configure DNS, or send messages by itself.
|
|
24
|
-
`cloudflare-email` supplies its existing Worker ingress, sending/outbox, feedback,
|
|
25
|
-
and provisioning integration. Other providers can call the core receiving APIs;
|
|
26
|
-
this release does not claim complete SES, Postmark, or generic outbound adapters.
|
|
27
|
-
The tests exercise Rails' stock Postmark HTTP ingress followed by explicit kit
|
|
28
|
-
attachment in one database; provider setup, dynamic envelope authorization and
|
|
29
|
-
provider outage behavior are separate integration responsibilities.
|
|
30
|
-
Inbound and outbound need not use the same service. A mailbox has no `provider`
|
|
31
|
-
attribute: receiving through one provider does not authorize sending through it.
|
|
9
|
+
Install `gem "mailbox-kit", "~> 0.1.0"`, or use the
|
|
10
|
+
[Cloudflare mailbox setup](https://github.com/cole-robertson/cloudflare-email/blob/main/docs/mailboxes.md)
|
|
11
|
+
when Cloudflare is your provider.
|
|
32
12
|
|
|
33
13
|
## Create an inbox
|
|
34
14
|
|
|
@@ -63,20 +43,13 @@ end
|
|
|
63
43
|
tenancy. Domain/address activation records evidence supplied by your trusted
|
|
64
44
|
application. It does not verify DNS or grant permission to send from that address.
|
|
65
45
|
|
|
66
|
-
`owner_ref`
|
|
67
|
-
|
|
68
|
-
Automatic `has_mailbox` owner bindings and deletion reconciliation are a separate
|
|
69
|
-
follow-up; this extraction does not introduce a callback that could silently
|
|
70
|
-
reassign an old address to a new owner.
|
|
46
|
+
`owner_ref` stores your application's reference to a user, team, or organization.
|
|
47
|
+
Use a stable identity and check access in your application.
|
|
71
48
|
|
|
72
|
-
##
|
|
49
|
+
## Attach an Action Mailbox record
|
|
73
50
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
callbacks, test helpers, and the development conductor at
|
|
77
|
-
`/rails/conductor/action_mailbox/inbound_emails`. The kit does not replace those.
|
|
78
|
-
Rails' `delivered` status means an inbound handler finished processing; read and
|
|
79
|
-
archive state belong to the kit's inbox membership instead.
|
|
51
|
+
Use ordinary `ApplicationMailbox` handlers for processing. Rails' `delivered`
|
|
52
|
+
status means processing finished; read and archive state belong to the inbox.
|
|
80
53
|
|
|
81
54
|
If an existing Rails ingress has already stored an email, attach that record:
|
|
82
55
|
|
|
@@ -127,7 +100,7 @@ The adapter remains responsible for authentication, authoritative envelope
|
|
|
127
100
|
recipients, delivery-specific identity where necessary, and retrying failed
|
|
128
101
|
requests. ActionMailbox still owns processing and its `ApplicationMailbox` routes.
|
|
129
102
|
|
|
130
|
-
|
|
103
|
+
To check application policy before saving, use a block:
|
|
131
104
|
|
|
132
105
|
```ruby
|
|
133
106
|
require "mailbox_kit/inbound_email"
|
|
@@ -140,12 +113,11 @@ end
|
|
|
140
113
|
Blocks must return the existing Rails record on duplicates if membership should
|
|
141
114
|
be attached. Rails' bare `create_and_extract_message_id!` returns `nil` for a
|
|
142
115
|
duplicate, so using it directly in that block can omit a second inbox membership.
|
|
143
|
-
Returning `nil`
|
|
116
|
+
Returning `nil` skips membership.
|
|
144
117
|
Neither a database transaction nor source deduplication guarantees exactly-once
|
|
145
118
|
business effects, external blob cleanup on rollback, or recovery of lost jobs.
|
|
146
119
|
|
|
147
|
-
|
|
148
|
-
metadata-based delivery identity, then uses the same Rails persistence bridge:
|
|
120
|
+
A custom Cloudflare endpoint can verify and receive in two steps:
|
|
149
121
|
|
|
150
122
|
```ruby
|
|
151
123
|
verified = Cloudflare::Email::Ingress.verify(
|
|
@@ -158,8 +130,8 @@ verified.message.receive_into_mailbox! if verified.status == :ok
|
|
|
158
130
|
The shipped Cloudflare ingress controller already does this, including HTTP error
|
|
159
131
|
handling and size limits. Installing the core does not add another HTTP endpoint
|
|
160
132
|
or SMTP server. `persist_action_mailbox!` remains available for applications that
|
|
161
|
-
only need Rails storage;
|
|
162
|
-
on duplicate. The
|
|
133
|
+
only need Rails storage; it returns the new record or `nil`
|
|
134
|
+
on duplicate. The inbox bridge can repair membership on duplicate delivery
|
|
163
135
|
without rerouting the email or replacing stored authentication metadata.
|
|
164
136
|
|
|
165
137
|
For an application with its own persistence, use
|
|
@@ -254,30 +226,9 @@ Never choose the tenant from request parameters. Rails framework jobs preserve t
|
|
|
254
226
|
explicit context; your own tenant jobs can `prepend MailboxKit::TenantJobContext`
|
|
255
227
|
after requiring `mailbox_kit/tenant_job_context`.
|
|
256
228
|
|
|
257
|
-
## Existing Cloudflare Email applications
|
|
258
|
-
|
|
259
|
-
Keep your existing requires, initializer, migrations, Worker and mounted engine.
|
|
260
|
-
Updating the Cloudflare gem brings in this core as a dependency. Public Cloudflare
|
|
261
|
-
constants resolve to the same core models; tables, IDs and tenant job payload keys
|
|
262
|
-
are retained. The `cloudflare_email_` table prefix is intentionally unchanged.
|
|
263
|
-
Do **not** run `mailbox_kit:install` over an existing Cloudflare mailbox schema.
|
|
264
|
-
|
|
265
|
-
For a fresh Cloudflare application, continue using the Cloudflare mailbox generator,
|
|
266
|
-
which also installs its outbox and event tables. A core-only installation should
|
|
267
|
-
not run both installers; adding Cloudflare outbound later needs its additional
|
|
268
|
-
tables and explicit sending-account/domain configuration. The receiving-only core
|
|
269
|
-
does not automatically become a Cloudflare sending account when the adapter loads.
|
|
270
|
-
|
|
271
229
|
## Sending from customer subdomains
|
|
272
230
|
|
|
273
231
|
Cloudflare onboards each sending domain/subdomain separately. Parent-domain
|
|
274
232
|
verification and wildcard receiving do not authorize arbitrary From subdomains.
|
|
275
233
|
Use an explicitly verified sending domain and, where useful, a customer-specific
|
|
276
234
|
inbound Reply-To. See [Cloudflare's subdomain rules](https://developers.cloudflare.com/email-service/configuration/subdomains/).
|
|
277
|
-
|
|
278
|
-
## Development and release
|
|
279
|
-
|
|
280
|
-
From the repository root, `bundle exec rake test` exercises both the compatibility
|
|
281
|
-
API and standalone core. `bundle exec ruby script/verify_package.rb` builds both
|
|
282
|
-
archives, installs a Rails-free consumer, and tests the packaged Rails integrations.
|
|
283
|
-
Publish `mailbox-kit` before releasing a Cloudflare version that depends on it.
|
|
@@ -3,12 +3,31 @@ require "mailbox_kit/tenancy"
|
|
|
3
3
|
|
|
4
4
|
module MailboxKit
|
|
5
5
|
module ActiveRecord
|
|
6
|
-
# Rails may inspect every model's pool while preloading schema metadata
|
|
7
|
-
# before any request has selected a tenant. Report an unavailable
|
|
8
|
-
# connection using Rails' error hierarchy so boot can recover, while
|
|
9
|
-
# retaining the same fail-closed guard for every caller.
|
|
10
6
|
class TenantConnectionUnavailable < ::ActiveRecord::ConnectionNotEstablished; end
|
|
11
7
|
|
|
8
|
+
# Returned instead of a pool while no valid tenant context is selected.
|
|
9
|
+
# Rails' production boot asks every model's pool for its schema reflection
|
|
10
|
+
# before any tenant exists (railtie "active_record.define_attribute_methods");
|
|
11
|
+
# raising there aborts that loop for every model still to come. This answers
|
|
12
|
+
# only that probe, with an empty reflection, and raises for anything else.
|
|
13
|
+
class UnavailablePool
|
|
14
|
+
def initialize(error)
|
|
15
|
+
@error = error
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def schema_reflection
|
|
19
|
+
::ActiveRecord::ConnectionAdapters::SchemaReflection.new(nil)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def method_missing(*)
|
|
23
|
+
raise TenantConnectionUnavailable, @error.message, cause: @error
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def respond_to_missing?(*)
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
12
31
|
# Uses the host's abstract tenant connection owner when explicitly configured.
|
|
13
32
|
class Base < Tenancy.model_base(::ActiveRecord::Base)
|
|
14
33
|
self.abstract_class = true
|
|
@@ -19,7 +38,7 @@ module MailboxKit
|
|
|
19
38
|
begin
|
|
20
39
|
Tenancy.require_context!
|
|
21
40
|
rescue ConfigurationError => error
|
|
22
|
-
|
|
41
|
+
return UnavailablePool.new(error)
|
|
23
42
|
end
|
|
24
43
|
end
|
|
25
44
|
super
|
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
require "mailbox-kit"
|
|
2
2
|
require "digest"
|
|
3
|
+
require "stringio"
|
|
3
4
|
|
|
4
5
|
module MailboxKit
|
|
5
6
|
# A small bridge to Rails' existing storage and routing lifecycle. It returns
|
|
6
7
|
# the existing record on duplicate delivery so callers can attach memberships.
|
|
8
|
+
#
|
|
9
|
+
# The raw source is uploaded BEFORE any transaction this module opens. A
|
|
10
|
+
# database transaction can hold a write lock (SQLite's from BEGIN when
|
|
11
|
+
# transactions are immediate), so a storage round trip inside one stalls
|
|
12
|
+
# every other writer. Call .prepare outside the caller's transaction too
|
|
13
|
+
# (Mailboxes.receive does) and only rows are written while it is open.
|
|
7
14
|
module InboundEmail
|
|
8
15
|
Result = Struct.new(:record, :created, keyword_init: true) do
|
|
9
16
|
def created? = created
|
|
10
17
|
end
|
|
11
18
|
|
|
12
19
|
def self.persist(source:, message_id: nil, message_checksum: nil, metadata: {})
|
|
20
|
+
prepare(source: source, message_id: message_id, message_checksum: message_checksum,
|
|
21
|
+
metadata: metadata).persist
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Resolves the identity and, unless a record already has it, uploads the raw
|
|
25
|
+
# email. Call in the tenant that will own the record, outside any
|
|
26
|
+
# transaction; then call #persist on the result.
|
|
27
|
+
def self.prepare(source:, message_id: nil, message_checksum: nil, metadata: {})
|
|
13
28
|
unless defined?(::ActionMailbox::InboundEmail)
|
|
14
29
|
raise ConfigurationError, "load ActionMailbox before persisting inbound mail"
|
|
15
30
|
end
|
|
@@ -33,24 +48,72 @@ module MailboxKit
|
|
|
33
48
|
end
|
|
34
49
|
identity = { message_id: message_id || "#{checksum}@mailbox-kit.invalid",
|
|
35
50
|
message_checksum: checksum }
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
Prepared.new(source, identity, metadata).tap(&:upload)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class Prepared
|
|
55
|
+
# The tenant the bytes were uploaded under, for a #discard run later.
|
|
56
|
+
attr_reader :tenant_key
|
|
57
|
+
|
|
58
|
+
def initialize(source, identity, metadata)
|
|
59
|
+
@source, @identity, @metadata = source, identity, metadata
|
|
60
|
+
@tenant_key = Tenancy.current_key if defined?(Tenancy)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Uploads the bytes unless a record with this identity already exists.
|
|
64
|
+
def upload
|
|
65
|
+
return if @blob || model.uncached { model.exists?(@identity) }
|
|
66
|
+
|
|
67
|
+
blob = ::ActiveStorage::Blob.new(filename: "message.eml", content_type: "message/rfc822",
|
|
68
|
+
service_name: ::ActionMailbox.storage_service, metadata: @metadata.to_h)
|
|
69
|
+
io = StringIO.new(@source)
|
|
70
|
+
blob.unfurl(io)
|
|
71
|
+
blob.upload_without_unfurling(io)
|
|
72
|
+
@blob = blob
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Writes the record and its blob row, or returns the record a concurrent
|
|
76
|
+
# delivery already wrote. Uploaded bytes no committed row will name are
|
|
77
|
+
# deleted once no transaction is open.
|
|
78
|
+
def persist
|
|
79
|
+
result = model.transaction do
|
|
80
|
+
# Uncached: a request's query cache would repeat #upload's answer.
|
|
81
|
+
if (existing = model.uncached { model.find_by(@identity) })
|
|
82
|
+
next Result.new(record: existing, created: false).freeze
|
|
49
83
|
end
|
|
50
|
-
|
|
84
|
+
# Rare: a record existed when #upload looked and is gone now.
|
|
85
|
+
upload
|
|
86
|
+
# Rails returns nil on a unique conflict. Roll back that savepoint before
|
|
87
|
+
# looking up the winner, including on PostgreSQL's aborted transactions.
|
|
88
|
+
record = model.transaction(requires_new: true) do
|
|
89
|
+
model.create!(raw_email: @blob, **@identity)
|
|
90
|
+
rescue ::ActiveRecord::RecordNotUnique
|
|
91
|
+
raise ::ActiveRecord::Rollback
|
|
92
|
+
end
|
|
93
|
+
Result.new(record: record || model.uncached { model.find_by!(@identity) }, created: !record.nil?).freeze
|
|
51
94
|
end
|
|
52
|
-
|
|
95
|
+
discard unless result.created?
|
|
96
|
+
result
|
|
97
|
+
rescue StandardError
|
|
98
|
+
discard unless model.connection.transaction_open?
|
|
99
|
+
raise
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Deletes the uploaded bytes unless a committed row names them. Run after
|
|
103
|
+
# the transaction that would have committed that row has finished.
|
|
104
|
+
def discard
|
|
105
|
+
return unless @blob
|
|
106
|
+
return if ::ActiveStorage::Blob.uncached { ::ActiveStorage::Blob.exists?(key: @blob.key) }
|
|
107
|
+
|
|
108
|
+
@blob.service.delete(@blob.key)
|
|
109
|
+
@blob = nil
|
|
110
|
+
rescue StandardError => error
|
|
111
|
+
warn "mailbox-kit: raw email #{@blob&.key} not deleted: #{error.class}: #{error.message}"
|
|
53
112
|
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def model = ::ActionMailbox::InboundEmail
|
|
54
117
|
end
|
|
55
118
|
end
|
|
56
119
|
end
|
|
@@ -39,15 +39,26 @@ module MailboxKit
|
|
|
39
39
|
raise ArgumentError, "provide source or a persistence block, not both" if source && block
|
|
40
40
|
raise ArgumentError, "source or persistence block required" unless source || block
|
|
41
41
|
in_recipient_tenant(recipient) do |session, address, directory|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
if source
|
|
43
|
+
# Upload before session.receive opens the membership transaction,
|
|
44
|
+
# and only for a destination that can accept it.
|
|
45
|
+
session.with_recipient(address, directory) { nil }
|
|
46
|
+
require "mailbox_kit/inbound_email"
|
|
47
|
+
prepared = InboundEmail.prepare(source: source)
|
|
48
|
+
end
|
|
49
|
+
begin
|
|
50
|
+
session.receive(address, directory) do |destination|
|
|
51
|
+
if block
|
|
52
|
+
# Legacy custom persistence blocks must return the existing Rails
|
|
53
|
+
# record on duplicates when membership attachment is desired.
|
|
54
|
+
block.lambda? && block.arity.zero? ? block.call : block.call(destination)
|
|
55
|
+
else
|
|
56
|
+
prepared.persist.record
|
|
57
|
+
end
|
|
50
58
|
end
|
|
59
|
+
ensure
|
|
60
|
+
# The transaction has finished: delete the upload if it rolled back.
|
|
61
|
+
prepared&.discard
|
|
51
62
|
end
|
|
52
63
|
end
|
|
53
64
|
end
|
data/lib/mailbox_kit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailbox-kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cole
|
|
@@ -27,7 +27,6 @@ files:
|
|
|
27
27
|
- app/views/mailbox_kit/management/mailboxes/message.html.erb
|
|
28
28
|
- app/views/mailbox_kit/management/mailboxes/show.html.erb
|
|
29
29
|
- docs/integration.md
|
|
30
|
-
- docs/upgrading.md
|
|
31
30
|
- lib/generators/mailbox_kit/install/install_generator.rb
|
|
32
31
|
- lib/generators/mailbox_kit/install/templates/create_mailbox_kit_mailboxes.rb
|
|
33
32
|
- lib/generators/mailbox_kit/install/templates/create_mailbox_kit_receiving_domains.rb
|
data/docs/upgrading.md
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Upgrading existing mailbox installations
|
|
2
|
-
|
|
3
|
-
The extracted core keeps existing `cloudflare_email_` tables, record IDs, public
|
|
4
|
-
Cloudflare constants and tenant job payloads. Keep your initializer, mounted
|
|
5
|
-
engine, Worker and application processing code. Do not run `mailbox_kit:install`
|
|
6
|
-
or the Cloudflare mailbox installer over existing mailbox tables.
|
|
7
|
-
|
|
8
|
-
After updating the gems, generate the index and receiving-domain migrations:
|
|
9
|
-
|
|
10
|
-
```sh
|
|
11
|
-
bin/rails generate mailbox_kit:upgrade
|
|
12
|
-
bin/rails db:migrate
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
For separate tenant databases:
|
|
16
|
-
|
|
17
|
-
```sh
|
|
18
|
-
bin/rails generate mailbox_kit:upgrade --tenant-migrations-path=db/tenant_migrate --directory-migrations-path=db/migrate
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Apply the index migration to every database containing mailbox messages using your
|
|
22
|
-
application's tenant migration runner. It does not belong in the shared domain
|
|
23
|
-
directory database. The migration preserves messages and skips an existing
|
|
24
|
-
single-column inbound index. New installers already include this index.
|
|
25
|
-
|
|
26
|
-
Apply `AllowProviderNeutralReceivingDomains` to the shared directory database.
|
|
27
|
-
It allows a null receiving-domain account ID, preserving existing account values.
|
|
28
|
-
Receiving-only registration requires no Cloudflare account; sending still requires
|
|
29
|
-
an explicit account and verified sending domain. On SQLite this schema change can
|
|
30
|
-
rebuild the directory table, so use your normal migration window.
|
|
31
|
-
|
|
32
|
-
Index creation can block writes on large tables. Plan its application according
|
|
33
|
-
to your database's normal migration procedure; PostgreSQL installations needing
|
|
34
|
-
online builds can adapt it to `algorithm: :concurrently` with
|
|
35
|
-
`disable_ddl_transaction!`.
|
|
36
|
-
|
|
37
|
-
## Verify the application upgrade
|
|
38
|
-
|
|
39
|
-
1. Receive a message through the existing authenticated provider integration.
|
|
40
|
-
2. Confirm it appears in the right inbox and runs the existing business handler.
|
|
41
|
-
3. Replay the delivery and confirm no duplicate business effects.
|
|
42
|
-
4. Check authorized and unauthorized UI access, read/archive actions, and retention.
|
|
43
|
-
5. For separate databases, exercise tenant routing and processing jobs in two tenants.
|
|
44
|
-
|
|
45
|
-
Keep your application's sender acceptance, ownership reconciliation and processing
|
|
46
|
-
claims. Rails processing status does not replace these business policies.
|
|
47
|
-
|
|
48
|
-
## Adding Cloudflare to a core-only application
|
|
49
|
-
|
|
50
|
-
The core's mailbox schema alone does not supply Cloudflare's outbox and event
|
|
51
|
-
tables. Add those provider tables and sending configuration explicitly using the
|
|
52
|
-
Cloudflare integration guide; do not run both complete installers against the
|
|
53
|
-
same database. Arbitrary subdomain receiving does not authorize sending from those
|
|
54
|
-
subdomains: verify each Cloudflare sending domain separately.
|
|
55
|
-
|
|
56
|
-
## Versions
|
|
57
|
-
|
|
58
|
-
Cloudflare Email 0.4.0 depends on Mailbox Kit 0.1.x and installs it automatically.
|
|
59
|
-
Core-only applications can install `gem "mailbox-kit", "~> 0.1.0"` directly.
|
|
60
|
-
Upgrade and verify your application's email flows before a wider rollout.
|