cloudflare-email 0.4.0 → 0.4.2

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -2
  3. data/README.md +63 -379
  4. data/SECURITY.md +1 -9
  5. data/docs/activerecord-tenanted.md +0 -11
  6. data/docs/custom-ingress.md +1 -15
  7. data/docs/delivery-events.md +2 -5
  8. data/docs/features.md +49 -123
  9. data/docs/getting-started.md +90 -172
  10. data/docs/mailboxes.md +24 -60
  11. data/docs/management-engine.md +1 -3
  12. data/docs/outbox.md +5 -6
  13. data/docs/reference.md +190 -0
  14. data/docs/routing-diagnostics.md +0 -2
  15. data/docs/thread-correlation.md +2 -4
  16. data/docs/troubleshooting.md +4 -4
  17. data/lib/cloudflare/email/client.rb +23 -5
  18. data/lib/cloudflare/email/ingress.rb +16 -4
  19. data/lib/cloudflare/email/version.rb +1 -1
  20. data/templates/deploy-to-cloudflare/README.md +8 -10
  21. data/templates/deploy-to-cloudflare/docs/domain-setup.md +86 -166
  22. data/templates/worker/README.md +6 -8
  23. data/templates/worker/docs/domain-setup.md +86 -166
  24. data/templates/worker/docs/durable-inbound.md +4 -16
  25. metadata +4 -19
  26. data/docs/architecture.md +0 -105
  27. data/docs/tenant-mailboxes-plan.md +0 -149
  28. data/docs/upgrading-0.2.md +0 -101
  29. data/docs/upgrading-0.3.md +0 -55
  30. data/docs/verification/2026-09-10-followup.md +0 -49
  31. data/docs/verification/2026-09-10-install-upgrade.md +0 -86
  32. data/docs/verification/2026-09-10-live.md +0 -102
  33. data/docs/verification/2026-09-10.md +0 -175
  34. data/docs/verification/2026-09-11-custom-ingress.md +0 -49
  35. data/docs/verification/2026-09-11-extraction.md +0 -32
  36. data/docs/verification/2026-09-11-outbound-ledger.md +0 -60
  37. data/docs/verification/2026-09-11-security.md +0 -76
  38. data/docs/verification/2026-09-11-tenant-mailboxes.md +0 -75
  39. data/docs/verification/2026-09-12-destination-context.md +0 -46
  40. data/docs/verification/2026-09-13-action-mailbox-core.md +0 -96
  41. data/docs/verification/2026-09-13-durable-inbound-and-routing.md +0 -71
@@ -1,26 +1,15 @@
1
- # Get email working in your Rails app
1
+ # Set up email in Rails
2
2
 
3
- This guide takes you from your first outgoing email to receiving replies and
4
- tracking deliveries. Start with sending and add the other pieces as needed.
5
- For a mailbox app, follow all four parts. **SQLite is supported throughout.**
3
+ This guide covers sending, receiving, and delivery tracking. For persistent
4
+ inboxes and a management UI, continue with [mailboxes](mailboxes.md).
5
+ SQLite works throughout.
6
6
 
7
- You will need an existing Rails app, a Cloudflare account, and a domain you can
8
- configure in Cloudflare. Use Ruby 3.2+ and a patched supported Rails release:
9
- tested floors are 7.2.3.2, 8.0.5.1 and 8.1.3.1. Rails 8 requires Ruby 3.3+.
10
- Ruby 4 is tested with Rails 8.1. Plain Ruby users can use the
11
- [standalone client](../README.md#plain-ruby) instead.
7
+ You need Rails 7.2–8.1, a Cloudflare account, and a domain you control.
8
+ These examples use `mail.example.com` for sending and `in.example.com` for receiving.
12
9
 
13
- Example addresses below use `mail.example.com` for sending and
14
- `in.example.com` for receiving. Replace them with subdomains you own. They do
15
- not need to be the same domain as your Rails application's web address.
10
+ ## 1. Install
16
11
 
17
- ## 1. Send your first email
18
-
19
- ### Install the current code
20
-
21
- Add version 0.4 to your app's `Gemfile`. Existing mailbox installations should read
22
- the [core upgrade guide](../mailbox-kit/docs/upgrading.md). When upgrading from 0.2,
23
- also read the [Worker upgrade guide](upgrading-0.3.md):
12
+ Add to your Gemfile:
24
13
 
25
14
  ```ruby
26
15
  gem "cloudflare-email", "~> 0.4.0"
@@ -28,44 +17,42 @@ gem "cloudflare-email", "~> 0.4.0"
28
17
 
29
18
  ```sh
30
19
  bundle install
31
- bin/rails generate cloudflare:email:install --no-inbound
20
+ bin/rails generate cloudflare:email:install
21
+ bin/rails db:migrate
32
22
  ```
33
23
 
34
- The generator creates an initializer that chooses `:cloudflare` as your
35
- ActionMailer delivery method. The `--no-inbound` option keeps this first step
36
- focused on sending; you can add receiving below.
24
+ Follow the prompts to install Action Mailbox and the default mailbox.
25
+ The generator also configures Action Mailer and copies the Worker template.
26
+ For a send-only app, use `--no-inbound` and skip the receiving steps below.
37
27
 
38
- ### Connect your sending domain
28
+ ## 2. Send your first email
39
29
 
40
- In Cloudflare, open **Compute → Email Service → Email Sending** and onboard
41
- your sending domain. Complete Cloudflare's DNS instructions and wait for domain
42
- verification. A dedicated subdomain helps keep an existing mail provider's apex
43
- configuration separate. Do not replace existing apex mail records casually.
30
+ In Cloudflare, open **Compute → Email Service → Email Sending**, add
31
+ `mail.example.com`, and complete its DNS verification. A sending subdomain lets
32
+ you keep your existing domain's mail provider.
44
33
 
45
- Create an account-scoped token with permission to send email. Add these variables
46
- to the environment where Rails runs, or use the equivalent Rails credentials:
34
+ Create a token with Email Sending permission and set:
47
35
 
48
36
  ```sh
49
37
  export CLOUDFLARE_ACCOUNT_ID=your-account-id
50
38
  export CLOUDFLARE_API_TOKEN=your-email-sending-token
51
39
  ```
52
40
 
53
- Rails credentials use `cloudflare.account_id` and `cloudflare.api_token`.
54
- Nonempty Rails credentials take precedence over environment variables. Keep
55
- real tokens out of committed files. Restart Rails after changing configuration.
41
+ Alternatively, use Rails credentials `cloudflare.account_id` and
42
+ `cloudflare.api_token`. Nonempty Rails credentials take precedence.
43
+ Restart Rails after changing configuration.
56
44
 
57
- ### Check the setup and send
45
+ Check the configuration and send to an inbox you control:
58
46
 
59
47
  ```sh
60
48
  bin/rails cloudflare:email:doctor
61
49
  FROM=hello@mail.example.com TO=you@example.net bin/rails cloudflare:email:send_test
62
50
  ```
63
51
 
64
- Use a destination inbox you control. `doctor` checks configuration and available
65
- read access; the second command actually sends mail. Confirm that it arrives,
66
- including checking spam. A diagnostics success alone does not prove delivery.
52
+ Check the destination inbox and spam folder. `doctor` checks configuration;
53
+ `send_test` sends the message.
67
54
 
68
- ### Use your regular mailers
55
+ ### Use your mailers
69
56
 
70
57
  ```ruby
71
58
  # app/mailers/hello_mailer.rb
@@ -76,80 +63,48 @@ class HelloMailer < ApplicationMailer
76
63
  end
77
64
  end
78
65
  end
79
- ```
80
-
81
- From `bin/rails console`:
82
66
 
83
- ```ruby
84
67
  HelloMailer.hello("you@example.net").deliver_now
85
68
  ```
86
69
 
87
- Your existing HTML templates, multipart messages, attachments and cc/bcc work
88
- through ActionMailer. Use `deliver_later` with your app's job backend for ordinary
89
- background delivery. For saved send history and protection against ambiguous
90
- resends, use the outbox in part 3. Do not send the same message through both paths.
70
+ Use `deliver_later` with your app's job backend for background sending.
71
+ HTML templates, attachments, multipart messages, and cc/bcc work through Action Mailer.
91
72
 
92
- ## 2. Receive email and replies
93
-
94
- Incoming email follows this path:
73
+ ## 3. Receive email
95
74
 
96
75
  ```text
97
- Sender → Cloudflare Email Routing → Email Worker → Rails ActionMailbox → your app
76
+ Sender → Cloudflare Email Routing → Worker → Rails Action Mailbox → your handler
98
77
  ```
99
78
 
100
- The Worker is a small program that forwards the email to Rails and signs it so
101
- Rails can verify the forwarding request. The installer supplies its code.
79
+ The Worker saves incoming email at Cloudflare and retries delivery while Rails
80
+ is unavailable.
102
81
 
103
- ### Install receiving support
82
+ ### Deploy the Worker
104
83
 
105
- ```sh
106
- bin/rails generate cloudflare:email:install
107
- bin/rails db:migrate
108
- ```
84
+ Save the generated secret as `cloudflare.ingress_secret` in Rails credentials
85
+ or `CLOUDFLARE_INGRESS_SECRET`. Deploy Rails with Active Storage and a running
86
+ job worker, then follow the [Deploy to Cloudflare guide](../templates/deploy-to-cloudflare/README.md).
109
87
 
110
- Follow the interactive prompts to install ActionMailbox and the default mailbox.
111
- If you already have custom mailbox routing or initializer changes, inspect the
112
- generator's overwrite prompts before accepting. The generated default mailbox
113
- only logs receipt; you will add your product's processing logic.
88
+ The deployment form asks for:
114
89
 
115
- Save the generated shared secret as `cloudflare.ingress_secret` in Rails
116
- credentials or `CLOUDFLARE_INGRESS_SECRET`. The deploy task copies that secret to
117
- the Worker. Use a separate deployment token as `cloudflare.management_token` or
118
- `CLOUDFLARE_MANAGEMENT_TOKEN`; [the permission table](../README.md#observability-and-permissions)
119
- lists the scopes needed for Worker deployment and routing.
90
+ - **RAILS_INGRESS_URL:** `https://app.example.com/rails/action_mailbox/cloudflare/inbound_emails`
91
+ - **INGRESS_SECRET:** the same secret configured in Rails
120
92
 
121
- ### Connect the receiving address
93
+ ### Connect an address
122
94
 
123
- In Cloudflare **Email Routing → your apex domain → Settings → Subdomains**, add
124
- your receiving subdomain, such as `in.example.com`, and finish its DNS setup.
125
- This is separate from verifying the sending domain.
95
+ In Cloudflare Email Routing, configure `in.example.com` and its receiving DNS
96
+ records. Create a rule for `support@in.example.com` with **Send to a Worker**,
97
+ selecting the deployed Worker.
126
98
 
127
- Deploy Rails with ActionMailbox storage and workers configured. For guided
128
- Worker setup, use the [Deploy to Cloudflare template](../templates/deploy-to-cloudflare/README.md).
129
- It provisions R2 and Queues and prompts for your Rails URL and shared secret.
130
- Then select that Worker in your Email Routing rule as described in its guide.
99
+ Sending-domain verification and receiving routes are separate.
100
+ For many addresses or customer subdomains, use the [domain setup guide](../templates/worker/docs/domain-setup.md).
131
101
 
132
- For the CLI setup instead, run these commands in an environment with production
133
- configuration and deployment credentials:
102
+ Send a test email to `support@in.example.com`. Confirm Rails stores it and
103
+ the mailbox job finishes.
134
104
 
135
- First create the private R2 bucket and Queue, then deploy the generated Wrangler
136
- configuration using the [durable setup guide](../templates/worker/docs/durable-inbound.md).
137
- The Ruby task below updates that provisioned Worker while preserving its bindings.
138
- It refuses a missing bucket/queue binding or recovery schedule before changing code.
105
+ ### Process the email
139
106
 
140
- ```sh
141
- RAILS_ENV=production bin/rails cloudflare:email:deploy_worker URL=https://app.example.com/rails/action_mailbox/cloudflare/inbound_emails
142
- RAILS_ENV=production bin/rails cloudflare:email:provision_route ADDRESS=support@in.example.com
143
- ```
144
-
145
- The first command deploys the Worker; the second routes the address to it.
146
- Send a real test email to `support@in.example.com`, then check the ActionMailbox
147
- record and processing job. A web request accepted by Rails means storage worked;
148
- the mailbox job can still need attention.
149
-
150
- ### Read the message in your mailbox
151
-
152
- Inside the generated `MainMailbox#process`, these values are available:
107
+ Add your application logic to the generated `MainMailbox#process`:
153
108
 
154
109
  ```ruby
155
110
  envelope = Cloudflare::Email::Envelope.for(inbound_email)
@@ -160,41 +115,32 @@ attachments = mail.attachments
160
115
  raw_message = inbound_email.raw_email.download
161
116
  ```
162
117
 
163
- Save or process those values using your application's models. For mailbox or
164
- tenant selection, use `receiving_address`, which comes from the authenticated
165
- SMTP envelope. MIME `To`/`Cc` headers may differ, especially for Bcc. The envelope
166
- can be absent for records from another ingress; handle that case explicitly.
167
- Treat message contents and attachments as untrusted input when displaying them.
118
+ Use the verified `receiving_address` for mailbox or organization lookup.
119
+ The MIME `To` header can differ, especially for Bcc. Treat message contents
120
+ and attachments as untrusted input.
168
121
 
169
- To direct replies to this address, add `reply_to: "support@in.example.com"` to
170
- your mailer's `mail(...)` call. For conversation matching, save the returned
171
- provider message ID and compare reply headers within your application's mailbox
172
- scope. The outbox saves this ID for you. See [thread correlation](thread-correlation.md).
122
+ Set `reply_to: "support@in.example.com"` in outgoing mail to receive replies here.
123
+ See [reply matching](thread-correlation.md) for conversations.
173
124
 
174
- ### Receive into a local Rails server
125
+ ### Test with a local Rails server
175
126
 
176
- Install `cloudflared`, configure development credentials and a separate development
177
- receiving route, then start Rails. In another terminal:
127
+ Install `cloudflared`, start Rails, and configure a separate development address.
128
+ Then run:
178
129
 
179
130
  ```sh
180
131
  INBOUND_DELIVERY_MODE=direct bin/rails cloudflare:email:deploy_worker
181
132
  bin/rails cloudflare:email:dev
182
133
  ```
183
134
 
184
- The first command creates the development Worker with the explicit direct fallback; the second points it at a
185
- temporary tunnel to your local Rails server on port 3000. Keep the tunnel running
186
- while testing and stop it with Ctrl-C. Set `PORT=...` if Rails uses another port.
187
- The task checks that Rails has the ingress-only guard; restart Rails if asked.
188
- Use development test data. The tunnel URL is temporary and does not provide an
189
- offline mailbox when your local server is stopped.
190
-
191
- ## 3. Add the durable outbox with SQLite
135
+ These commands need a [Worker management token](reference.md#observability-and-permissions).
136
+ Keep the tunnel running while testing. It uses port 3000 by default;
137
+ set `PORT=...` for another port. Direct mode does not retain mail while
138
+ your local server is stopped.
192
139
 
193
- An outbox saves the exact message before sending it. Background jobs reference
194
- that saved operation instead of re-rendering and resending mail on every retry.
195
- This is useful for compose, replies, invoices and approved drafts.
140
+ ## 4. Save outgoing messages
196
141
 
197
- If your Rails app already uses SQLite, keep its database configuration. Run:
142
+ The outbox saves a message before sending, tracks each recipient, and protects
143
+ against accidental resends after a timeout.
198
144
 
199
145
  ```sh
200
146
  bin/rails generate cloudflare:email:tracking
@@ -202,33 +148,26 @@ bin/rails generate cloudflare:email:outbox
202
148
  bin/rails db:migrate
203
149
  ```
204
150
 
205
- These add the receipt and delivery tables plus opt-in initializers. Skip a
206
- generator whose migration you already installed. Configure a durable ActiveJob
207
- backend and run a worker that processes the `mailers` queue; the gem does not
208
- install the backend for you.
151
+ If you are setting up [managed mailboxes](mailboxes.md), use that generator
152
+ instead—it includes both of these.
209
153
 
210
- Try this from Rails console, outside an existing database transaction:
154
+ With a job worker processing the `mailers` queue, try this from Rails console:
211
155
 
212
156
  ```ruby
213
157
  account_id = Cloudflare::Email::Credentials.account_id
214
158
  operation = Cloudflare::Email::ActiveRecord::Outbox.prepare_mail(
215
159
  account_id: account_id,
216
- operation_key: "getting-started:hello:1",
160
+ operation_key: "hello:1",
217
161
  mail: HelloMailer.hello("you@example.net").message,
218
162
  )
219
163
  Cloudflare::Email::SendJob.perform_later(account_id, operation.operation_key)
220
164
  ```
221
165
 
222
- The operation key identifies **one intended send** in your account. Save it with
223
- your product record. For a genuinely new message use a new key; for a job retry
224
- reuse the saved identity. Do not re-render a mailer and call `prepare_mail` as
225
- your retry mechanism: generated MIME headers can change, causing a snapshot conflict.
226
-
227
- In an application transaction, prepare the operation alongside your business
228
- record, then enqueue only after the outer transaction commits. The detailed
229
- [outbox guide](outbox.md#prepare-once-dispatch-after-commit) shows that pattern.
166
+ Use one operation key per intended send. For retries, dispatch the saved
167
+ operation rather than rendering and sending the mailer again.
168
+ In application transactions, enqueue after commit.
230
169
 
231
- After the worker runs, inspect the result:
170
+ Inspect the result:
232
171
 
233
172
  ```ruby
234
173
  operation.reload.state
@@ -236,26 +175,23 @@ operation.provider_message_id
236
175
  operation.outbound_recipients.pluck(:recipient, :acceptance_state, :state)
237
176
  ```
238
177
 
239
- `accepted` means all recipients have provider acceptance evidence; `partial`
240
- means only some do. Neither promises that a human received or read the message.
241
- `unknown` or a stuck `sending` operation needs investigation, not a new send key
242
- as a shortcut. See [states and recovery](outbox.md#states-and-retries).
178
+ See the [outbox guide](outbox.md) for application transactions, callbacks,
179
+ and recovery of uncertain sends.
243
180
 
244
- ## 4. Track delivery, bounces and complaints
181
+ ## 5. Track delivery
245
182
 
246
- Cloudflare sends later delivery updates through a Queue. You configure that
247
- Queue and its Email Sending subscription once; your app polls it regularly.
248
- Follow [the provisioning steps](delivery-events.md#provision-once), including an
249
- HTTP pull consumer, retries and a dead-letter queue for repeatedly failing events.
183
+ Create an outbound Cloudflare Queue and Email Sending subscription using the
184
+ [delivery-event setup](delivery-events.md#provision-once). This is a separate
185
+ queue from the inbound Worker queue.
250
186
 
251
- Add a separate queue token and queue ID to your Rails environment:
187
+ Set:
252
188
 
253
189
  ```sh
254
190
  export CLOUDFLARE_QUEUES_TOKEN=your-queues-read-write-token
255
191
  export CLOUDFLARE_EVENT_QUEUE_ID=your-queue-id
256
192
  ```
257
193
 
258
- With the outbox installed, configure this initializer:
194
+ With the outbox installed, configure:
259
195
 
260
196
  ```ruby
261
197
  # config/initializers/cloudflare_delivery_events.rb
@@ -269,41 +205,23 @@ Rails.application.configure do
269
205
  end
270
206
  ```
271
207
 
272
- Restart Rails and poll a batch:
208
+ Restart Rails and run:
273
209
 
274
210
  ```sh
275
211
  bin/rails cloudflare:email:consume_events
276
- ```
277
-
278
- This command processes **one batch and exits**. Schedule it repeatedly using
279
- your application's scheduler. Also schedule receipt replay for recovery:
280
-
281
- ```sh
282
212
  bin/rails cloudflare:email:replay_events
283
213
  ```
284
214
 
285
- The gem saves receipts before acknowledgement, handles duplicates, and matches
286
- updates to the account, provider message ID and recipient. If an event arrives
287
- before the send result is saved, it stays available for replay. Recipient state
288
- then reflects delivered, deferred, bounced, failed, rejected or complained events.
289
- Your app still decides what those outcomes mean for its UI and future sending.
290
-
291
- For custom product updates, use the [transactional callbacks](outbox.md#recover-dispatch-and-application-projections).
292
- If you only want events and have your own delivery models, use the lower-level
293
- [durable receipt adapter](delivery-events.md#durable-rails-receipts).
294
-
295
- ## Before relying on it
215
+ Each command runs once and exits; schedule both to run regularly.
216
+ Receipts are saved before acknowledgement and matched to the message's
217
+ recipients. Delivery states include delivered, deferred, bounced, failed,
218
+ rejected, and complained.
296
219
 
297
- Send to an external inbox you control, reply back, verify stored attachments,
298
- and confirm a real queue event updates the intended recipient. Keep a durable
299
- job worker running and schedule recovery of `prepared` operations that might
300
- have committed before enqueueing. Monitor stuck operations and failed mailbox jobs.
220
+ ## Check your setup
301
221
 
302
- Protect stored MIME and attachments, choose retention and backup policies, and
303
- set proxy/server request limits. The default incoming raw message limit is
304
- 25 MiB; set the same positive `MAX_EMAIL_BYTES` on Rails and the Worker if you
305
- override it. Cloudflare has separate [outgoing size and recipient limits](https://developers.cloudflare.com/email-service/platform/limits/).
222
+ Send to an external inbox, reply back, check the stored attachment, and confirm
223
+ a delivery event updates the intended recipient. Keep Rails jobs and event
224
+ polling running, and monitor failed jobs and the Worker's pending mail.
306
225
 
307
- Use [troubleshooting](troubleshooting.md) when something does not arrive,
308
- [the feature overview](features.md) to explore more, and
309
- [the upgrade guide](upgrading-0.3.md) for an existing 0.1 installation.
226
+ Next: [create inboxes](mailboxes.md), [add the management UI](management-engine.md),
227
+ or [troubleshoot missing mail](troubleshooting.md).
data/docs/mailboxes.md CHANGED
@@ -3,15 +3,10 @@
3
3
  The optional mailbox module lets your app create mailboxes and aliases, receive
4
4
  mail into them, track read/archive state, and send through the durable outbox.
5
5
  It works in one SQLite database or with a separate database per organization.
6
- It supplies models and services; your app supplies permissions and the UI.
6
+ Use the [management UI](management-engine.md) or build your own interface with these APIs.
7
7
 
8
- This module is available since version 0.2.0. Install `gem "cloudflare-email", "~> 0.4.0"` for the latest features, including the provider-neutral Mailbox Kit core.
9
-
10
- **Database multi-tenancy is off by default.** The mailbox generator works with
11
- one ordinary database. Calling `for_tenant` groups and scopes mailbox records;
12
- it does not create databases or install a tenant adapter. Separate databases
13
- require explicit `Tenancy.configure(...)` before models load. Neither Rails nor
14
- `activerecord-tenanted` is added to plain Ruby applications by this module.
8
+ **Database multi-tenancy is off by default.** `for_tenant` scopes records in your
9
+ existing database. [Separate databases](activerecord-tenanted.md) require explicit setup.
15
10
 
16
11
  ## Install
17
12
 
@@ -22,20 +17,19 @@ bin/rails generate cloudflare:email:mailboxes
22
17
  bin/rails db:migrate
23
18
  ```
24
19
 
25
- The generator includes the outbox and tracking generators. Do not generate those
26
- migrations a second time if you already installed them; inspect existing
27
- generator conflicts and retain your installed migrations. Restart Rails after
28
- configuration changes. The generated initializer explicitly loads:
20
+ The generator includes the outbox and tracking setup. Keep any migrations you
21
+ have already installed. Restart Rails after configuration changes.
22
+ The generated initializer loads:
29
23
 
30
24
  ```ruby
31
25
  require "cloudflare/email/mailboxes"
32
26
  ```
33
27
 
34
28
  Loading this module enables mailbox lookup on the gem's Cloudflare ingress.
35
- Existing receiving addresses must be registered and activated before switching
36
- an existing application over. Unregistered or suspended destinations return
37
- HTTP 422 and the Worker rejects the delivery by default. You can explicitly
38
- configure a domain catch-all below when your application needs that behavior.
29
+ Register and activate each accepted address. Unregistered or suspended destinations
30
+ return HTTP 422. In the default durable Worker mode, the email stays pending at
31
+ Cloudflare until you resolve the destination. Enable a domain catch-all below if
32
+ you want unknown local parts to enter an inbox.
39
33
 
40
34
  For separate organization databases, follow the
41
35
  [activerecord-tenanted setup](activerecord-tenanted.md) **before loading the
@@ -47,10 +41,7 @@ use the same tenant connection as the mailbox tables for atomic incoming storage
47
41
 
48
42
  For addresses such as `invoices@acme.in.example.com`, follow the
49
43
  [Cloudflare domain setup guide](../templates/worker/docs/domain-setup.md).
50
- It covers Rebulk's existing wildcard receiving pattern, one-time infrastructure
51
- verification, and exact organization-domain registration in Rails. The gem does
52
- not require a per-organization Worker allowlist or Cloudflare approval once that
53
- receiving infrastructure is established; new accounts must verify the provider behavior.
44
+ It covers receiving DNS, Worker routing, and registering customer domains in Rails.
54
45
 
55
46
  Run directory management from your authorized administration/provisioning code.
56
47
  Do not expose arbitrary domain claims to customers without ownership checks.
@@ -151,30 +142,14 @@ suspension is an administrative update of `ReceivingDomain#state` to `suspended`
151
142
 
152
143
  Addresses use lowercase ASCII dot-atom local parts and domains. Alias addresses
153
144
  are explicit: the module does not automatically strip `+tags` or invent address
154
- fallbacks. Reserve application-specific names such as Rebulk's `tracking` in
145
+ fallbacks. Reserve application-specific names such as `tracking` in
155
146
  your mailbox-management policy before creation.
156
147
 
157
148
  ## Receive unregistered local parts with an optional catch-all
158
149
 
159
- Catch-all receiving is **off by default** and is available in the 0.3
160
- version. It lets one existing address receive otherwise unregistered addresses
161
- on its exact domain, without creating an alias row for each incoming local part.
162
- For example, `anything@acme.example.com` can arrive in an existing support mailbox.
163
- It does not cover subdomains such as `anything@other.acme.example.com`.
164
-
165
- Fresh installations include the schema. For an existing installation, generate
166
- the optional upgrade and apply it to the database containing your mailbox tables:
167
-
168
- ```sh
169
- bin/rails generate cloudflare:email:mailboxes:catch_all
170
- bin/rails db:migrate
171
- ```
172
-
173
- With separate tenant databases, pass
174
- `--tenant-migrations-path=db/tenant_migrate` and run your application's tenant
175
- migration command for every affected tenant. Updating the gem alone keeps older
176
- schemas working with exact-address routing. Enabling a catch-all without its
177
- migration raises a configuration error.
150
+ Catch-all receiving is **off by default**. It lets one inbox receive unregistered
151
+ local parts on its exact domain. For example, `anything@acme.example.com` can
152
+ arrive in your support inbox. It does not cover `anything@other.acme.example.com`.
178
153
 
179
154
  First configure and verify the domain's catch-all Email Routing rule in Cloudflare
180
155
  to send mail to your Worker. Then use your authorized provisioning code:
@@ -348,23 +323,12 @@ the same tenant connection when atomicity is required. External effects cannot
348
323
  be rolled back. Provider acceptance, shared storage and tenant storage are not
349
324
  one transaction; this is not exactly-once delivery.
350
325
 
351
- ## Isolation and rollout
352
-
353
- The scoped session API checks tenant/mailbox ownership and sender addresses.
354
- It does not authenticate Rails users. Protect admin directory APIs, choose the
355
- tenant through your access resolver, and authorize every mailbox operation.
356
- Direct/unscoped ActiveRecord access is an application-level privileged interface,
357
- particularly in shared-database mode; it is not a row-level authorization system.
358
-
359
- For database tenancy, configure all framework storage on the tenant connection
360
- and exclude ingress from hostname/session tenant selection. New framework jobs
361
- capture tenant context before serialization and restore it before GlobalID
362
- lookup. Drain existing ActionMailbox/ActiveStorage queues before enabling this
363
- mode: previously serialized jobs without the new metadata are rejected.
364
-
365
- The gem does not create organizations/users, verify customer domain ownership,
366
- provide IMAP/POP, or supply a full compose/conversation inbox. The optional
367
- [management engine](management-engine.md) supplies mailbox administration and
368
- plain-text previews using your host's access policy. The original Rebulk document-processing
369
- Worker contract and sender-review policy still need a separate application
370
- migration; installing this module does not replace that live pipeline.
326
+ ## Permissions
327
+
328
+ Choose the tenant from your authenticated application context and authorize each
329
+ mailbox operation. The scoped APIs check mailbox ownership within that tenant;
330
+ direct Active Record access requires your own permission checks.
331
+
332
+ For separate databases, use the [tenant connection guide](activerecord-tenanted.md)
333
+ to configure framework storage and jobs. Your app supplies users, sender policy,
334
+ and business processing.
@@ -1,12 +1,10 @@
1
- # Optional mailbox management engine
1
+ # Mailbox management UI
2
2
 
3
3
  The management engine is a small, server-rendered Rails interface for the
4
4
  [managed mailbox APIs](mailboxes.md). It works with ordinary Rails apps and with
5
5
  apps using Inertia, React, Turbo or another frontend. No JavaScript, Node build,
6
6
  asset pipeline or frontend package is required for the engine.
7
7
 
8
- This feature is available in RubyGems 0.3.0.
9
-
10
8
  ## What you get
11
9
 
12
10
  - Mailbox lists, names, creation and aliases on allowed receiving domains.
data/docs/outbox.md CHANGED
@@ -166,10 +166,9 @@ For a partial operation, only unresolved recipients can be reconciled. Omit `rec
166
166
 
167
167
  For a `sending` operation, first stop the original sender and verify it cannot resume. Reconciliation additionally requires `confirm_sender_stopped: true` and a claim at least 15 minutes old. Elapsed time alone is insufficient. There is no automatic lease expiry or timeout-based resend.
168
168
 
169
- ## Data ownership and migration
169
+ ## Stored data
170
170
 
171
- The gem owns its operation, recipient, receipt, and reconciliation infrastructure. The inbox owns mailbox permissions, conversations, approval policy, AI drafts, and UI. Link product records to operations by a stable key or application foreign key instead of copying the ledger algorithm.
172
-
173
- The MIME snapshot contains email bodies, addresses, and attachments. Apply your application's database access, encryption, backup, and retention policies. Removing ledgers or replaying old backups can discard uncertainty and deduplication evidence; quiesce sending and reconcile provider activity during recovery.
174
-
175
- Importing historical attempts is application-specific. If the old application did not save exact MIME, a reconstructed snapshot is historical metadata, not proof of the original bytes. Preserve its known/unknown state and do not turn imported accepted or uncertain attempts into dispatchable `prepared` operations. The generated outbox and receipt migrations refuse rollback to preserve delivery and deduplication evidence; use a forward fix or a reconciled backup.
171
+ The outbox saves message bodies, addresses, attachments, and delivery history.
172
+ Apply your application's database access, encryption, backup, and retention policies.
173
+ Keep deduplication and acceptance evidence when restoring data so a recovery
174
+ does not resend accepted mail.