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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +59 -2
- data/README.md +63 -379
- data/SECURITY.md +1 -9
- data/docs/activerecord-tenanted.md +0 -11
- data/docs/custom-ingress.md +1 -15
- data/docs/delivery-events.md +2 -5
- data/docs/features.md +49 -123
- data/docs/getting-started.md +90 -172
- data/docs/mailboxes.md +24 -60
- data/docs/management-engine.md +1 -3
- data/docs/outbox.md +5 -6
- data/docs/reference.md +190 -0
- data/docs/routing-diagnostics.md +0 -2
- data/docs/thread-correlation.md +2 -4
- data/docs/troubleshooting.md +4 -4
- data/lib/cloudflare/email/client.rb +23 -5
- data/lib/cloudflare/email/ingress.rb +16 -4
- data/lib/cloudflare/email/version.rb +1 -1
- data/templates/deploy-to-cloudflare/README.md +8 -10
- data/templates/deploy-to-cloudflare/docs/domain-setup.md +86 -166
- data/templates/worker/README.md +6 -8
- data/templates/worker/docs/domain-setup.md +86 -166
- data/templates/worker/docs/durable-inbound.md +4 -16
- metadata +4 -19
- data/docs/architecture.md +0 -105
- data/docs/tenant-mailboxes-plan.md +0 -149
- data/docs/upgrading-0.2.md +0 -101
- data/docs/upgrading-0.3.md +0 -55
- data/docs/verification/2026-09-10-followup.md +0 -49
- data/docs/verification/2026-09-10-install-upgrade.md +0 -86
- data/docs/verification/2026-09-10-live.md +0 -102
- data/docs/verification/2026-09-10.md +0 -175
- data/docs/verification/2026-09-11-custom-ingress.md +0 -49
- data/docs/verification/2026-09-11-extraction.md +0 -32
- data/docs/verification/2026-09-11-outbound-ledger.md +0 -60
- data/docs/verification/2026-09-11-security.md +0 -76
- data/docs/verification/2026-09-11-tenant-mailboxes.md +0 -75
- data/docs/verification/2026-09-12-destination-context.md +0 -46
- data/docs/verification/2026-09-13-action-mailbox-core.md +0 -96
- data/docs/verification/2026-09-13-durable-inbound-and-routing.md +0 -71
data/docs/getting-started.md
CHANGED
|
@@ -1,26 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Set up email in Rails
|
|
2
2
|
|
|
3
|
-
This guide
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
20
|
+
bin/rails generate cloudflare:email:install
|
|
21
|
+
bin/rails db:migrate
|
|
32
22
|
```
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
28
|
+
## 2. Send your first email
|
|
39
29
|
|
|
40
|
-
In Cloudflare, open **Compute → Email Service → Email Sending
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
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
|
|
54
|
-
Nonempty Rails credentials take precedence
|
|
55
|
-
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
|
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
|
-
|
|
88
|
-
|
|
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
|
-
##
|
|
93
|
-
|
|
94
|
-
Incoming email follows this path:
|
|
73
|
+
## 3. Receive email
|
|
95
74
|
|
|
96
75
|
```text
|
|
97
|
-
Sender → Cloudflare Email Routing →
|
|
76
|
+
Sender → Cloudflare Email Routing → Worker → Rails Action Mailbox → your handler
|
|
98
77
|
```
|
|
99
78
|
|
|
100
|
-
The Worker
|
|
101
|
-
|
|
79
|
+
The Worker saves incoming email at Cloudflare and retries delivery while Rails
|
|
80
|
+
is unavailable.
|
|
102
81
|
|
|
103
|
-
###
|
|
82
|
+
### Deploy the Worker
|
|
104
83
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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
|
-
|
|
116
|
-
|
|
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
|
|
93
|
+
### Connect an address
|
|
122
94
|
|
|
123
|
-
In Cloudflare
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
128
|
-
|
|
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
|
-
|
|
133
|
-
|
|
102
|
+
Send a test email to `support@in.example.com`. Confirm Rails stores it and
|
|
103
|
+
the mailbox job finishes.
|
|
134
104
|
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
170
|
-
|
|
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
|
-
###
|
|
125
|
+
### Test with a local Rails server
|
|
175
126
|
|
|
176
|
-
Install `cloudflared`,
|
|
177
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
206
|
-
|
|
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
|
-
|
|
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: "
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
240
|
-
|
|
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
|
-
##
|
|
181
|
+
## 5. Track delivery
|
|
245
182
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
308
|
-
[
|
|
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
|
-
|
|
6
|
+
Use the [management UI](management-engine.md) or build your own interface with these APIs.
|
|
7
7
|
|
|
8
|
-
|
|
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
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
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
|
|
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
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
##
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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.
|
data/docs/management-engine.md
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
#
|
|
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
|
-
##
|
|
169
|
+
## Stored data
|
|
170
170
|
|
|
171
|
-
The
|
|
172
|
-
|
|
173
|
-
|
|
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.
|