react-email-rails 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bbfbb40c2044856c9061ba2a3c134d07dbd5aa9b58b6cfe3d576d25fe45b4d2
4
- data.tar.gz: 7c272a65e71044f813c813b248a48bc69e3a043494ad9f6133ae8c69ab006b24
3
+ metadata.gz: 4755984b895a6aa5f220079065da541f8b8da23dc905095fb5cae48471fb2096
4
+ data.tar.gz: 66568a9bd36727d453904f765b2eb73b3aff4b8335b59de57d34933f1e4a4b8a
5
5
  SHA512:
6
- metadata.gz: c5b434f0983a8c1280d622203869f535a0c98fb293bcfff3d51d39a8676d730d000b901cb9bcc6b3b478fe633904974798131482e44982140f40e12951ac1423
7
- data.tar.gz: 21652f85cc0ee448ec90ffd7b24c4eaf05b892dbe0e83d487777ae57bbcda7a34c46e1b9becad9174838edd0d33919b11aa9efb56cbd520433803c8a3fd82385
6
+ metadata.gz: d5b407fd84acd1a1f162fe412f5d1ee611a0fdd095a2923b2a38ef2c63e366023a513fa26c09453fbbc1c9821c3681bb2838713dfdcf463dd8c767cdc5375b5c
7
+ data.tar.gz: 81f890f4900c9dae7631073bb68b66941642456fc895a81a3a78620f7e719df506ead6dcf5fddc38ab746182f544054f243f111968839e99e512e1a89eb0fe4b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1
4
+
5
+ - Fix `react:` rendering — and the `mailer`/`message` props — being skipped for actions that opt in through a class-level `default react: true` rather than a per-`mail` `react:` option. `mail` now resolves `react` (in any form: `true`, a component string, or a prop hash) from the mailer's `default`, a per-action `react: false` opts back out, and the internal `react`/`props`/`deep_merge` options never leak onto the message as email headers.
6
+
7
+ ## 0.6.0
8
+
9
+ - Every `react:` email now receives `mailer` and `message` props, mirroring Action Mailer's `mailer`/`message` ERB view helpers. Rendering now happens after Action Mailer assigns headers, so `message` includes subject, addressing, and default `from`/`reply_to` values. Per-mail and shared props win on conflict, serializers whose `as_json` returns a Hash receive the context, and collection props keep their original shape. The npm package exports matching `Mailer`/`Message` TypeScript types.
10
+
3
11
  ## 0.5.0
4
12
 
5
13
  - Add `react_email_share` for sharing props across every `react:` email a mailer renders, mirroring inertia-rails' `inertia_share`. Supports static values, lazy lambdas and blocks (evaluated in the mailer instance), `only`/`except`/`if`/`unless` filters, and subclass inheritance. Per-mail props win over shared props.
data/README.md CHANGED
@@ -2,15 +2,36 @@
2
2
 
3
3
  # react-email-rails
4
4
 
5
- Build and send emails using React and Rails with [React Email](https://react.email) and [Action Mailer](https://guides.rubyonrails.org/action_mailer_basics.html).
5
+ Build and send Action Mailer emails with [React Email](https://react.email), TypeScript, and Vite.
6
+
7
+ react-email-rails lets Rails render React Email components into HTML and plain text, then deliver them through the Action Mailer stack you already know: previews, headers, callbacks, queues, instrumentation, and delivery all keep working normally.
8
+
9
+ ## Why
10
+
11
+ HTML email is still awkward. React Email gives you a nicer component model, email-safe primitives, Tailwind support, and TypeScript. This gem connects that workflow to Rails without replacing Action Mailer.
12
+
13
+ You get:
14
+
15
+ - React Email components rendered from `mail(...)`
16
+ - HTML and plain-text output from the same component
17
+ - Rails mailer previews, tests, queues, callbacks, and delivery
18
+ - Vite-powered development rendering
19
+ - A production renderer bundle built during `assets:precompile`
20
+ - Optional persistent rendering for high-volume workers
21
+ - Optional server-side rendering for `@react-email/editor` documents
22
+
23
+ ## Status
24
+
25
+ react-email-rails is pre-1.0. It was extracted from [XOXO](https://xoxo.email), which is pre-launch, so the API may still change and it has not yet been battle-tested in high-volume production.
26
+
27
+ The supported Ruby, Rails, Node, React, and Vite versions are tested in CI. Please [open an issue](https://github.com/heysupertape/react-email-rails/issues) for bugs, rough edges, or integration feedback.
6
28
 
7
29
  ## Contents
8
30
 
9
- - [Why](#why)
10
- - [How](#how)
11
- - [Status](#status)
12
31
  - [Requirements](#requirements)
13
- - [Quick Start](#quick-start)
32
+ - [Installation](#installation)
33
+ - [Your First Email](#your-first-email)
34
+ - [How Rendering Works](#how-rendering-works)
14
35
  - [Usage](#usage)
15
36
  - [Configuration](#configuration)
16
37
  - [Deployment](#deployment)
@@ -19,73 +40,58 @@ Build and send emails using React and Rails with [React Email](https://react.ema
19
40
  - [Security](#security)
20
41
  - [License](#license)
21
42
 
22
- ## Why
23
-
24
- Building HTML emails is painfully archaic. [React Email](https://react.email) brings React, Tailwind, and TypeScript to email templates. This gem wires it into Action Mailer so React components deliver as generated HTML and text emails.
25
-
26
- ## How
27
-
28
- **In development,** the gem renders components live through Vite's dev pipeline, so your emails get the same module resolution and transforms as the rest of your frontend.
29
-
30
- **In production,** Rails builds a server-side renderer bundle during `assets:precompile` using `reactEmailRails()` in your Vite config for discovery and options.
31
-
32
- react-email-rails automatically renders both HTML and plain-text versions from the same component. Delivery, headers, previews, queues, and callbacks all stay normal Action Mailer. If rendering fails, no email is sent and `ReactEmailRails::RenderError` is raised.
33
-
34
- ## Status
35
-
36
- **react-email-rails is pre-1.0.** It was extracted from [XOXO](https://xoxo.email) which is pre-launch, so it hasn't been battle-tested in high-volume production environments yet. It's tested in CI across the supported Ruby, Rails, Node, and Vite versions, but the API may still change before 1.0. Please [share feedback and report issues](https://github.com/heysupertape/react-email-rails/issues).
37
-
38
43
  ## Requirements
39
44
 
40
- - Ruby >= 3.3
41
- - Action Mailer, Active Support, and Railties >= 7.1 and < 9.0
42
- - Node >= 20.19
43
- - Vite 7 or 8
44
- - React 18 or 19
45
- - `@react-email/render` 2.x
45
+ | Dependency | Version |
46
+ |------------|---------|
47
+ | Ruby | >= 3.3 |
48
+ | Rails | Action Mailer, Active Support, and Railties >= 7.1 and < 9.0 |
49
+ | Node | >= 20.19 |
50
+ | Vite | 7 or 8 |
51
+ | React | 18 or 19 |
52
+ | `@react-email/render` | 2.x |
46
53
 
47
- > We recommend [rails_vite](https://github.com/skryukov/rails_vite/) for Vite with Rails.
54
+ We recommend [rails_vite](https://github.com/skryukov/rails_vite/) for Vite in Rails apps.
48
55
 
49
- ## Quick Start
56
+ ## Installation
50
57
 
51
- Add the gem:
58
+ Add the Ruby gem:
52
59
 
53
60
  ```ruby
54
61
  # Gemfile
55
-
56
62
  gem "react-email-rails"
57
63
  ```
58
64
 
59
- ### Automatic Install
60
-
61
- Run the installer:
65
+ Then install it with Rails:
62
66
 
63
67
  ```sh
68
+ bundle install
64
69
  bin/rails generate react_email_rails:install
65
70
  ```
66
71
 
67
- This creates `config/initializers/react_email_rails.rb`, installs missing JavaScript dependencies when it can detect your package manager, adds `reactEmailRails()` to `vite.config.*`, and creates `app/javascript/emails`.
72
+ The installer creates `config/initializers/react_email_rails.rb`, installs missing JavaScript dependencies when it can detect your package manager, adds `reactEmailRails()` to `vite.config.*`, and creates `app/javascript/emails`.
68
73
 
69
- The installed setup then follows the normal Rails lifecycle:
74
+ After installation, the normal Rails flow applies:
70
75
 
71
- - `bin/rails generate react_email_rails:email ...` creates matching mailers and React components.
72
- - `bin/dev` renders through Vite on demand.
73
- - `bin/rails assets:precompile` builds the production renderer bundle automatically.
74
- - `bin/rails react_email_rails:build` builds the bundle directly when CI or tests need it.
76
+ - Generate mailers and components with `bin/rails generate react_email_rails:email ...`.
77
+ - Run `bin/dev` in development; email components render through Vite on demand.
78
+ - Run `bin/rails assets:precompile` for production; the renderer bundle builds automatically.
79
+ - Run `bin/rails react_email_rails:build` directly when CI or tests need the bundle without the full asset task.
75
80
 
76
- ### Manual Install
81
+ ### Manual Setup
77
82
 
78
- Install the npm package and peer dependencies manually:
83
+ If you prefer to wire things up yourself, install the npm package and React Email dependencies:
79
84
 
80
85
  ```sh
81
86
  npm i react-email-rails @react-email/render @react-email/components react react-dom
82
87
  ```
83
88
 
84
- Update your Vite config to add the plugin:
89
+ Use the equivalent command for pnpm, Yarn, or Bun if your app uses a different package manager.
90
+
91
+ Then add the Vite plugin:
85
92
 
86
93
  ```ts
87
94
  // vite.config.ts
88
-
89
95
  import { defineConfig } from "vite"
90
96
  import { reactEmailRails } from "react-email-rails"
91
97
 
@@ -94,7 +100,7 @@ export default defineConfig({
94
100
  })
95
101
  ```
96
102
 
97
- ### Your First Email
103
+ ## Your First Email
98
104
 
99
105
  Generate a mailer and React Email component:
100
106
 
@@ -102,13 +108,15 @@ Generate a mailer and React Email component:
102
108
  bin/rails generate react_email_rails:email Account welcome
103
109
  ```
104
110
 
105
- The generator follows Rails' mailer generator shape: `NAME [method method]`. It creates the mailer, matching React components, a mailer preview, and a test. It reads `emails.path` and `emails.extension` from `reactEmailRails()` when available. Pass flags to override them:
111
+ The generator follows Rails' mailer generator shape: `NAME [method method]`. It creates a mailer, React component, mailer preview, and test. It also reads `emails.path` and `emails.extension` from `reactEmailRails()` when available.
112
+
113
+ Pass flags when you need to override the detected component directory or extension:
106
114
 
107
115
  ```sh
108
116
  bin/rails generate react_email_rails:email Account welcome --emails-path=app/emails --extension=jsx
109
117
  ```
110
118
 
111
- Edit the generated mailer to pass any necessary props:
119
+ Update the generated mailer to pass props into the React component:
112
120
 
113
121
  ```ruby
114
122
  class AccountMailer < ApplicationMailer
@@ -128,11 +136,10 @@ class AccountMailer < ApplicationMailer
128
136
  end
129
137
  ```
130
138
 
131
- Edit the generated email component:
139
+ Then edit the generated component:
132
140
 
133
141
  ```tsx
134
142
  // app/javascript/emails/account_mailer/welcome.tsx
135
-
136
143
  import { Body, Container, Html, Text } from "@react-email/components"
137
144
 
138
145
  type WelcomeProps = {
@@ -154,29 +161,70 @@ export default function Welcome({ account }: WelcomeProps) {
154
161
  }
155
162
  ```
156
163
 
157
- > [@react-email/components](https://react.email/docs/components/html) provides primitives like `<Button>`, `<Heading>`, `<Tailwind>`, and more.
164
+ Deliver it like any other Action Mailer email:
165
+
166
+ ```ruby
167
+ AccountMailer.with(account: current_account).welcome.deliver_later
168
+ ```
169
+
170
+ React Email also provides primitives like [`<Button>`, `<Heading>`, `<Tailwind>`, and more](https://react.email/docs/components/html).
171
+
172
+ ## How Rendering Works
173
+
174
+ In development, react-email-rails renders components through Vite's dev pipeline. Your email components get the same module resolution and transforms as the rest of your frontend.
175
+
176
+ In production, `assets:precompile` builds a server-side renderer bundle from your Vite config. Rails runs that bundle with Node whenever an email needs to render.
158
177
 
159
- That's it. It now renders and delivers like any other Action Mailer email.
178
+ Every `react:` email renders HTML and plain text from the same component. If rendering fails, the email is not sent and `ReactEmailRails::RenderError` is raised.
160
179
 
161
180
  ## Usage
162
181
 
163
- Pass data from your mailer and each top-level key becomes a prop on the component's default export. Our API mirrors [inertia-rails](https://inertia-rails.dev), making the two libraries feel consistent when used together.
182
+ ### Passing Props
183
+
184
+ Top-level keys passed to `react:` become props on the component's default export. The API is intentionally close to [inertia-rails](https://inertia-rails.dev), so apps using both libraries should feel consistent.
164
185
 
165
186
  ```ruby
166
- mail react: { foo: "bar" }, ...
187
+ mail(
188
+ to: account.email,
189
+ subject: "Welcome",
190
+ react: {
191
+ account: {
192
+ name: account.name,
193
+ },
194
+ },
195
+ )
167
196
  ```
168
197
 
169
198
  ```tsx
170
- export default function Email({ foo }: { foo: string }) {
199
+ type WelcomeProps = {
200
+ account: {
201
+ name: string
202
+ }
203
+ }
204
+
205
+ export default function Welcome({ account }: WelcomeProps) {
171
206
  // ...
172
207
  }
173
208
  ```
174
209
 
175
- ### Props
210
+ ### Component Inference
211
+
212
+ By default, react-email-rails infers the component from the mailer and action:
213
+
214
+ | Mailer action | Component |
215
+ |---------------|-----------|
216
+ | `AccountMailer#welcome` | `account_mailer/welcome` |
217
+ | `Users::InviteMailer#new_invite` | `users/invite_mailer/new_invite` |
218
+
219
+ `AccountMailer#welcome` resolves to `app/javascript/emails/account_mailer/welcome.tsx` or `.jsx` with the default Vite options.
176
220
 
177
- Choose the level of inference you want for your props:
221
+ Use `react: true` to render the inferred component. By default it renders with no props, which is handy for emails that take none:
178
222
 
179
- #### Implicit Component, Instance Props
223
+ ```ruby
224
+ mail(to: account.email, subject: "Welcome", react: true)
225
+ ```
226
+
227
+ To have `react: true` build props automatically, enable `use_react_instance_props`. The component then receives the mailer's instance variables as props:
180
228
 
181
229
  ```ruby
182
230
  class AccountMailer < ApplicationMailer
@@ -184,33 +232,30 @@ class AccountMailer < ApplicationMailer
184
232
 
185
233
  def welcome
186
234
  @account = params.fetch(:account)
187
- mail react: true, to: @account.email, subject: "Welcome"
235
+
236
+ mail(to: @account.email, subject: "Welcome", react: true)
188
237
  end
189
238
  end
190
239
  ```
191
240
 
192
- Action Mailer's framework assigns (including `params` and `rendered_format`) are excluded from instance props.
193
-
194
- Without `use_react_instance_props`, `react: true` still infers the component and renders it with no props, which is handy for emails that take no props at all.
241
+ Action Mailer's framework assigns, including `params` and `rendered_format`, are excluded from instance props.
195
242
 
196
- #### Implicit Component, Explicit Props
243
+ To make React the default for every action, set `default react: true` on the mailer (or `ApplicationMailer`). Each `mail` call then renders the inferred component without repeating `react: true`, and a single action can opt back out with `react: false`:
197
244
 
198
245
  ```ruby
199
- mail(
200
- ...
201
- react: {
202
- account: {
203
- name: account.name,
204
- },
205
- },
206
- )
246
+ class ApplicationMailer < ActionMailer::Base
247
+ default react: true
248
+ end
207
249
  ```
208
250
 
209
- #### Explicit Component, Explicit Props
251
+ ### Explicit Components
252
+
253
+ Pass a component name when the mailer action and component path do not line up:
210
254
 
211
255
  ```ruby
212
256
  mail(
213
- ...
257
+ to: account.email,
258
+ subject: "Welcome",
214
259
  react: "accounts/welcome",
215
260
  props: {
216
261
  account: {
@@ -220,110 +265,168 @@ mail(
220
265
  )
221
266
  ```
222
267
 
268
+ To change naming globally, override `component_path_resolver` in your [Rails configuration](#rails-configuration).
269
+
223
270
  ### Shared Props
224
271
 
225
- Use `react_email_share` to share data with all of a mailer's emails and subclasses, and it'll be automatically merged with any inline props.
272
+ Use `react_email_share` to merge props into every `react:` email for a mailer and its subclasses:
226
273
 
227
274
  ```ruby
228
275
  class MarketingMailer < ApplicationMailer
229
- # Static value
230
276
  react_email_share app_name: "Acme"
231
277
 
232
- # Lambda value, evaluated lazily in the mailer instance
233
- react_email_share unread_count: -> { current_user&.unread_count }
278
+ react_email_share unread_count: -> { params[:account]&.unread_count }
234
279
 
235
- # Block, evaluated lazily in the mailer instance
236
280
  react_email_share do
237
281
  { brand: { name: "Acme", url: marketing_url } }
238
282
  end
239
283
  end
240
284
  ```
241
285
 
242
- Per-mail props win over shared props of the same name, so a mailer can always override what it inherits:
286
+ Per-mail props win over shared props of the same name:
243
287
 
244
288
  ```ruby
245
- mail react: { app_name: "Acme Pro" }, ... # overrides the shared app_name
289
+ mail(
290
+ to: account.email,
291
+ subject: "Welcome",
292
+ react: {
293
+ app_name: "Acme Pro",
294
+ },
295
+ )
246
296
  ```
247
297
 
248
- Shared props apply to all three forms above (`react:` hash, `react: "component", props:`, and `react: true`).
298
+ Shared props work with `react:` hashes, `react: true`, and explicit `react: "component", props: ...` calls.
249
299
 
250
- #### Conditional Sharing
300
+ ### Conditional Shared Props
251
301
 
252
- Pass any `before_action` filter (`only`, `except`, `if`, `unless`) to scope a share to certain actions:
302
+ `react_email_share` accepts the same filter options as `before_action`: `only`, `except`, `if`, and `unless`.
253
303
 
254
304
  ```ruby
255
305
  react_email_share only: [:welcome, :reactivation] do
256
- { promotion: current_promotion }
306
+ { promotion: params.fetch(:promotion) }
257
307
  end
258
308
 
259
- react_email_share if: :user_signed_in? do
260
- { user: { name: current_user.name } }
309
+ react_email_share if: :account_active? do
310
+ { account: { name: params.fetch(:account).name } }
261
311
  end
262
312
  ```
263
313
 
264
- You can also share from inside an action, before calling `mail`:
314
+ You can also share props inside an action before calling `mail`:
265
315
 
266
316
  ```ruby
267
317
  def welcome
318
+ account = params.fetch(:account)
319
+
268
320
  react_email_share notice: "Thanks for joining!"
269
- mail react: { account: }, to: account.email, subject: "Welcome"
321
+
322
+ mail(
323
+ to: account.email,
324
+ subject: "Welcome",
325
+ react: { account: account.as_json(only: [:name]) },
326
+ )
270
327
  end
271
328
  ```
272
329
 
273
- #### Deep Merging
330
+ ### Deep Merging Shared Props
331
+
332
+ Shared props are merged shallowly by default. That means a per-mail prop replaces a shared prop with the same name.
274
333
 
275
- By default shared props are merged shallowly, so a per-mail prop replaces a shared one of the same name outright. Pass `deep_merge: true` to merge nested hashes instead:
334
+ Pass `deep_merge: true` to merge nested hashes instead:
276
335
 
277
336
  ```ruby
278
337
  react_email_share do
279
338
  { settings: { theme: "light", locale: "en" } }
280
339
  end
281
340
 
282
- # Shallow (default): settings => { theme: "dark" }
283
- mail react: { settings: { theme: "dark" } }, ...
341
+ mail(
342
+ to: account.email,
343
+ subject: "Welcome",
344
+ react: {
345
+ settings: {
346
+ theme: "dark",
347
+ },
348
+ },
349
+ deep_merge: true,
350
+ )
351
+ ```
352
+
353
+ The component receives:
284
354
 
285
- # Deep: settings => { theme: "dark", locale: "en" }
286
- mail react: { settings: { theme: "dark" } }, deep_merge: true, ...
355
+ ```ruby
356
+ { settings: { theme: "dark", locale: "en" } }
287
357
  ```
288
358
 
289
- Set `config.deep_merge_shared_props = true` to make deep merging the default for every email. (See [Configuration](#configuration))
359
+ Set `config.deep_merge_shared_props = true` to make deep merging the default for every email.
290
360
 
291
- ### Prop Serialization
361
+ ### Mailer and Message Props
292
362
 
293
- Like `render json:`, `mail react:` accepts any object that responds to `as_json`, including hashes, Active Model objects, and serializers such as [Alba](https://github.com/okuramasafumi/alba) or [ActiveModel::Serializer](https://github.com/rails-api/active_model_serializers).
363
+ Every `react:` email receives `mailer` and `message` props, mirroring the [`mailer` and `message` view helpers](https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-view-helpers) available to Action Mailer ERB views.
294
364
 
295
- ### Prop Transformation
365
+ `mailer` identifies the mailer action. `message` reflects the email after Action Mailer has assigned headers and defaults, including default `from` and `reply_to` values. With the default prop transform, import the `Mailer` and `Message` types to annotate them:
296
366
 
297
- Prop keys are camelized by default, so `account.plan_name` arrives as `account.planName`. Override `transform_props` in your [configuration](#configuration).
367
+ ```tsx
368
+ import type { Mailer, Message } from "react-email-rails"
369
+ import { Body, Container, Html, Text } from "@react-email/components"
298
370
 
299
- ### Component Names
371
+ type WelcomeProps = {
372
+ account: { name: string }
373
+ mailer: Mailer
374
+ message: Message
375
+ }
300
376
 
301
- Component names are inferred from the mailer and action:
377
+ export default function Welcome({ account, mailer, message }: WelcomeProps) {
378
+ return (
379
+ <Html>
380
+ <Body>
381
+ <Container>
382
+ <Text>Welcome, {account.name}</Text>
383
+ <Text>Re: {message.subject}</Text>
384
+ </Container>
385
+ </Body>
386
+ </Html>
387
+ )
388
+ }
389
+ ```
302
390
 
303
- | Mailer action | Component |
304
- |---------------|-----------|
305
- | `AccountMailer#welcome` | `account_mailer/welcome` |
306
- | `Users::InviteMailer#new_invite` | `users/invite_mailer/new_invite` |
391
+ | Prop | Example |
392
+ |------|---------|
393
+ | `mailer.mailerName` | `"account_mailer"` |
394
+ | `mailer.actionName` | `"welcome"` |
395
+ | `message.subject` | `"Welcome"` |
396
+ | `message.to` | `["account@example.com"]` |
397
+ | `message.cc`, `message.bcc` | `["…"]` or `null` |
398
+ | `message.from`, `message.replyTo` | `["app@example.com"]` |
399
+
400
+ Context is merged before prop serialization, so keys follow `config.transform_props` just like your own props. The exported TypeScript types describe the default `:lower_camel` shape.
307
401
 
308
- Rails derives `account_mailer` from `AccountMailer` via `mailer_name`. By default, `account_mailer/welcome` resolves to `app/javascript/emails/account_mailer/welcome.tsx` or `.jsx`.
402
+ Per-mail and shared props win on conflict, so a prop named `mailer` or `message` overrides the injected context. Serializer props receive the context when `as_json` returns a hash. Collections, arrays, and other non-object values pass through unchanged so their top-level shape is preserved.
309
403
 
310
- Files and directories starting with `_` are ignored as renderable email entries by default. Use them for shared components such as `_components/email_layout.tsx`. They can still be imported by email components.
404
+ ### Prop Serialization
311
405
 
312
- Override the inferred name per mail:
406
+ Props are serialized with `as_json`, just like `render json:`. You can pass hashes, arrays, Active Model objects, and serializer output from libraries such as [Alba](https://github.com/okuramasafumi/alba) or [ActiveModel::Serializer](https://github.com/rails-api/active_model_serializers).
313
407
 
314
- ```ruby
315
- mail react: "users/welcome", props: { user: }, to:, subject:
408
+ Prop keys are camelized by default, so `plan_name` arrives in React as `planName`. See [Prop Transformation](#prop-transformation) to change that behavior.
409
+
410
+ ### Component Files
411
+
412
+ Files and directories starting with `_` are ignored as renderable email entries by default. Use them for shared components, layouts, and helpers:
413
+
414
+ ```text
415
+ app/javascript/emails/
416
+ account_mailer/
417
+ welcome.tsx
418
+ _components/
419
+ email_layout.tsx
316
420
  ```
317
421
 
318
- Or override `component_path_resolver` globally in your [configuration](#configuration).
422
+ Ignored files can still be imported by email components.
319
423
 
320
424
  ### Layouts
321
425
 
322
- Action Mailer layouts aren't applied to `react:` emails. React Email treats layouts like any other component, so share structure with normal React composition instead:
426
+ Action Mailer layouts are not applied to `react:` emails. In React Email, layouts are normal React components:
323
427
 
324
428
  ```tsx
325
429
  // app/javascript/emails/_components/email_layout.tsx
326
-
327
430
  import { Body, Container, Html } from "@react-email/components"
328
431
  import type { ReactNode } from "react"
329
432
 
@@ -344,7 +447,6 @@ export function EmailLayout({ children }: EmailLayoutProps) {
344
447
 
345
448
  ```tsx
346
449
  // app/javascript/emails/account_mailer/welcome.tsx
347
-
348
450
  import { Text } from "@react-email/components"
349
451
  import { EmailLayout } from "../_components/email_layout"
350
452
 
@@ -357,21 +459,28 @@ export default function Welcome() {
357
459
  }
358
460
  ```
359
461
 
360
- See [Component Names](#component-names) for how shared `_` files are handled.
462
+ ### Editor Documents
361
463
 
362
- ### Editor
363
-
364
- If you're also using [@react-email/editor](https://react.email/docs/editor) to let users compose emails inside your app, `ReactEmailRails.compose` can render those stored documents on the server.
464
+ If your app uses [@react-email/editor](https://react.email/docs/editor) to let users compose emails visually, `ReactEmailRails.compose` can render stored editor documents on the server.
365
465
 
366
466
  See [Editor rendering](docs/editor.md) for setup and usage.
367
467
 
368
468
  ## Configuration
369
469
 
370
- Configuration is handled primarily on the Rails side, though there are some Vite options to be aware of.
470
+ Configuration lives in two places:
471
+
472
+ - Rails configuration controls mailer behavior, prop handling, rendering mode, timeouts, and error hooks.
473
+ - Vite configuration controls email component discovery and the renderer bundle.
371
474
 
372
475
  ### Rails Configuration
373
476
 
374
- If the defaults don't fit, override them in `config/initializers/react_email_rails.rb`:
477
+ Override Rails-side defaults in `config/initializers/react_email_rails.rb`:
478
+
479
+ ```ruby
480
+ ReactEmailRails.configure do |config|
481
+ # config.render_mode = :persistent
482
+ end
483
+ ```
375
484
 
376
485
  | Option | Default |
377
486
  |--------|---------|
@@ -384,14 +493,14 @@ If the defaults don't fit, override them in `config/initializers/react_email_rai
384
493
  | `on_render_error` | `nil` |
385
494
  | `deep_merge_shared_props` | `false` |
386
495
 
387
- #### Prop Transformation
496
+ ### Prop Transformation
388
497
 
389
- Set `transform_props` to another supported value if you prefer a different prop key style:
498
+ Set `transform_props` to choose how Ruby prop keys are exposed to React:
390
499
 
391
500
  | Value | Example |
392
501
  |-------|---------|
393
502
  | `:camel` | `AccountName` |
394
- | `:lower_camel` (default) | `accountName` |
503
+ | `:lower_camel` | `accountName` |
395
504
  | `:dash` | `account-name` |
396
505
  | `:snake` | `account_name` |
397
506
  | `:none` | preserves serialized keys |
@@ -402,15 +511,15 @@ ReactEmailRails.configure do |config|
402
511
  end
403
512
  ```
404
513
 
405
- `transform_props` only controls prop key names. Props are always serialized with `as_json`.
514
+ Only prop keys are transformed. Values are always serialized with `as_json`.
406
515
 
407
- #### Render Modes
516
+ ### Render Modes
408
517
 
409
- `:subprocess` starts a fresh Node process for each render. It's simple, isolated, and always uses the latest bundle, but pays Node startup and bundle load each time.
518
+ The default `:subprocess` mode starts a fresh Node process for each render. It is simple, isolated, and always uses the latest bundle, but it pays Node startup and bundle load time for each email.
410
519
 
411
- `:persistent` reuses one long-lived Node process per worker. It's faster for render-heavy workers, but uses more memory and can serve a stale component until recycled. The default `:subprocess` mode is usually enough. Switch when Node startup shows up in traces or batch jobs render many emails from the same bundle.
520
+ `:persistent` mode keeps one long-lived Node child process per Ruby process. It is faster for render-heavy workers, but uses more memory and can serve a stale component until the child is recycled.
412
521
 
413
- Enable persistent mode for render-heavy worker processes:
522
+ Switch to persistent mode when Node startup shows up in traces or when a worker renders many emails from the same bundle:
414
523
 
415
524
  ```ruby
416
525
  ReactEmailRails.configure do |config|
@@ -418,21 +527,22 @@ ReactEmailRails.configure do |config|
418
527
  end
419
528
  ```
420
529
 
421
- Persistent mode keeps one Node child per process:
530
+ Persistent mode details:
422
531
 
423
- - Renders are newline-delimited JSON and processed one at a time. Scale throughput with more worker processes.
424
- - It's fork-safe: under clustered Puma or forking job runners, each worker spawns its own child.
425
- - The child is recycled after `render_process_max_requests` renders to bound memory growth. Set it to `nil` to disable recycling.
532
+ - Renders are newline-delimited JSON and processed one at a time.
533
+ - Throughput scales with more worker processes.
534
+ - It is fork-safe; clustered Puma and forking job runners spawn one Node child per worker.
535
+ - The child recycles after `render_process_max_requests` renders. Set that option to `nil` to disable recycling.
426
536
 
427
- #### Render Options
537
+ ### Render Options
428
538
 
429
- `render_options` is passed to [@react-email/render](https://react.email/docs/utilities/render). Use `html` and `text` keys for each output. Option keys are camelized before they cross into JavaScript.
539
+ `render_options` is passed to [@react-email/render](https://react.email/docs/utilities/render). Use `html` and `text` keys to configure each output. Option keys are camelized before they cross into JavaScript.
430
540
 
431
541
  ```ruby
432
542
  ReactEmailRails.configure do |config|
433
543
  config.render_options = {
434
544
  html: {
435
- pretty: Rails.env.development?
545
+ pretty: Rails.env.development?,
436
546
  },
437
547
  text: {
438
548
  html_to_text_options: {
@@ -443,9 +553,11 @@ ReactEmailRails.configure do |config|
443
553
  end
444
554
  ```
445
555
 
446
- #### Error Reporting
556
+ `render_options` can also be a callable. When rendering from a mailer, it is evaluated in the mailer instance so it can use helpers or per-email state.
557
+
558
+ ### Error Reporting
447
559
 
448
- Use `on_render_error` to report failures before the exception is re-raised. The callback receives the error plus `kind:` and `component:`:
560
+ Use `on_render_error` to report failures before the exception is re-raised:
449
561
 
450
562
  ```ruby
451
563
  ReactEmailRails.configure do |config|
@@ -455,33 +567,50 @@ ReactEmailRails.configure do |config|
455
567
  end
456
568
  ```
457
569
 
458
- #### Instrumentation
570
+ The callback receives the error plus render context such as `kind:` and `component:`.
459
571
 
460
- Every render emits `render.react-email-rails` through [ActiveSupport::Notifications](https://guides.rubyonrails.org/active_support_instrumentation.html). The payload includes `kind`, `component`, and successful HTML size in `html_bytes`:
572
+ ### Instrumentation
573
+
574
+ Every render emits `render.react-email-rails` through [ActiveSupport::Notifications](https://guides.rubyonrails.org/active_support_instrumentation.html). Email payloads include `kind`, `component`, and successful HTML size in `html_bytes`.
461
575
 
462
576
  ```ruby
463
577
  ActiveSupport::Notifications.subscribe("render.react-email-rails") do |event|
464
- Rails.logger.info("[react-email-rails] Rendered #{event.payload[:component]} (Duration: #{event.duration.round}ms | Size: #{event.payload[:html_bytes]} bytes)")
578
+ Rails.logger.info(
579
+ "[react-email-rails] Rendered #{event.payload[:component]} " \
580
+ "(#{event.duration.round}ms, #{event.payload[:html_bytes]} bytes)",
581
+ )
465
582
  end
466
583
  ```
467
584
 
468
585
  ### Vite Configuration
469
586
 
470
- Most apps only need the `reactEmailRails()` plugin from [Quick Start](#quick-start). The options below change component discovery, bundle dependency handling, and isolated renderer transforms.
587
+ Most apps only need the plugin from [Installation](#installation):
588
+
589
+ ```ts
590
+ import { defineConfig } from "vite"
591
+ import { reactEmailRails } from "react-email-rails"
592
+
593
+ export default defineConfig({
594
+ plugins: [reactEmailRails()],
595
+ })
596
+ ```
471
597
 
472
- In development and production, the isolated renderer loads `reactEmailRails()`, JSX support, and component-facing Vite config such as `resolve`, `define`, `css`, `json`, `assetsInclude`, `esbuild`, and `oxc`. It doesn't load your other app plugins. Server, preview, dependency optimization, and build output settings stay owned by react-email-rails.
598
+ The isolated renderer loads `reactEmailRails()`, JSX support, and component-facing Vite config such as `resolve`, `define`, `css`, `json`, `assetsInclude`, `esbuild`, and `oxc`. It does not load your other app plugins unless you explicitly add them with `vite.plugins`.
473
599
 
474
- #### Plugin Options
600
+ Server, preview, dependency optimization, and build output settings stay owned by react-email-rails so Rails can always find the renderer bundle.
601
+
602
+ ### Vite Plugin Options
475
603
 
476
604
  | Option | Default | Description |
477
605
  |--------|---------|-------------|
478
606
  | `emails.path` | `"app/javascript/emails"` | Directory containing email components |
479
607
  | `emails.extension` | `[".tsx", ".jsx"]` | Component extension, or an array of extensions |
480
608
  | `emails.ignore` | `["**/_*", "**/_*/**"]` | Glob patterns ignored under `emails.path` |
609
+ | `documents` | `false` | Optional `@react-email/editor` document renderer discovery; see [Editor rendering](docs/editor.md) |
481
610
  | `standalone` | `true` | Inline production renderer bundle dependencies |
482
611
  | `vite` | `{}` | Extra email-only Vite config for compilation and resolution |
483
612
 
484
- Use a custom directory:
613
+ Use a custom email directory:
485
614
 
486
615
  ```ts
487
616
  reactEmailRails({
@@ -489,7 +618,7 @@ reactEmailRails({
489
618
  })
490
619
  ```
491
620
 
492
- Use multiple extensions:
621
+ Use custom extensions:
493
622
 
494
623
  ```ts
495
624
  reactEmailRails({
@@ -499,11 +628,11 @@ reactEmailRails({
499
628
  })
500
629
  ```
501
630
 
502
- Component names come from the Vite directory layout (see [Component Names](#component-names)). To map mailer actions to a different layout, override `component_path_resolver` on the Ruby side rather than renaming in the plugin, so both halves stay in sync.
631
+ Component names come from the Vite directory layout. To map mailer actions to a different layout, override `component_path_resolver` on the Ruby side so both halves stay in sync.
503
632
 
504
- #### Advanced: Email-Only Vite Plugins
633
+ ### Email-Only Vite Plugins
505
634
 
506
- Most apps don't need extra email plugins. If email components need a transform that isn't part of Vite's default pipeline, add that transform to the isolated renderer:
635
+ Most apps do not need extra email plugins. If email components need a transform that is not part of Vite's default pipeline, add it to the isolated renderer:
507
636
 
508
637
  ```ts
509
638
  import mdx from "@mdx-js/rollup"
@@ -521,13 +650,13 @@ export default defineConfig({
521
650
  })
522
651
  ```
523
652
 
524
- These `vite` options are used by `react-email-rails-dev` and `react-email-rails-build`. Only `assetsInclude`, `css`, `define`, `esbuild`, `json`, `oxc`, `plugins`, and `resolve` are accepted. Output settings such as `build.outDir` and `build.rollupOptions` are ignored so Ruby can always find the bundle.
653
+ Only `assetsInclude`, `css`, `define`, `esbuild`, `json`, `oxc`, `plugins`, and `resolve` are accepted inside `vite`. Output settings such as `build.outDir` and `build.rollupOptions` are ignored.
525
654
 
526
- #### Standalone Builds
655
+ ### Standalone Builds
527
656
 
528
- By default the production renderer bundle inlines React, `@react-email/render`, and other Node dependencies. This works well for Rails deploys that build assets in one stage and run without `node_modules` in the final image. Development previews keep dependencies external, even when `standalone` is enabled.
657
+ By default, the production renderer bundle inlines React, `@react-email/render`, and other Node dependencies. This works well for Rails deploys that build assets in one stage and run without `node_modules` in the final image.
529
658
 
530
- Set `standalone: false` when your runtime already ships `node_modules` and you prefer a smaller SSR-style bundle:
659
+ Set `standalone: false` when your runtime ships `node_modules` and you prefer a smaller SSR-style bundle:
531
660
 
532
661
  ```ts
533
662
  reactEmailRails({
@@ -535,45 +664,43 @@ reactEmailRails({
535
664
  })
536
665
  ```
537
666
 
538
- Externalized bundles are smaller and may build faster, but the renderer needs the externalized packages available at runtime.
667
+ Externalized bundles can be smaller and may build faster, but the externalized packages must be available at runtime.
539
668
 
540
669
  ## Deployment
541
670
 
542
- For production deploys, run the normal Rails asset task:
671
+ Production deploys should run the normal Rails asset task:
543
672
 
544
673
  ```sh
545
674
  bin/rails assets:precompile
546
675
  ```
547
676
 
548
- The `react_email_rails:build` task is hooked into `assets:precompile` automatically. It loads `reactEmailRails()` options from your Vite config, then writes `tmp/react-email-rails/emails.js` with the email component registry. If [Editor document rendering](docs/editor.md) is enabled, the bundle also includes document renderers.
677
+ react-email-rails hooks `react_email_rails:build` into `assets:precompile`. The build task loads `reactEmailRails()` options from your Vite config and writes `tmp/react-email-rails/emails.js` with the email component registry. If [Editor rendering](docs/editor.md) is enabled, the bundle also includes document renderers.
549
678
 
550
- You can run it directly when needed:
679
+ You can run the renderer build directly:
551
680
 
552
681
  ```sh
553
682
  bin/rails react_email_rails:build
554
683
  ```
555
684
 
556
- Production rendering runs that bundle with Node. Set `SKIP_REACT_EMAIL_RAILS_BUILD=1` to skip the automatic asset hook. Directly running `bin/rails react_email_rails:build` always attempts the build.
557
-
558
- The npm package, Vite, React, and `@react-email/render` must be available when Rails runs `assets:precompile`. If you enable [Editor document rendering](docs/editor.md), its peer dependencies must be available too.
685
+ Production rendering requires that bundle. If it is missing, rendering raises `ReactEmailRails::RenderError` and Action Mailer does not send the email.
559
686
 
560
- The bundle is required, not an optimization. If it's missing, renders raise `ReactEmailRails::RenderError`. Action Mailer deliveries aren't sent.
687
+ Set `SKIP_REACT_EMAIL_RAILS_BUILD=1` to skip the automatic asset hook. Directly running `bin/rails react_email_rails:build` always attempts the build.
561
688
 
562
- The Ruby gem and npm package must stay on the same version. The renderer includes a small protocol/version handshake, so mismatched installs fail with an actionable `ReactEmailRails::RenderError` instead of silently returning malformed output.
689
+ The npm package, Vite, React, and `@react-email/render` must be available when Rails runs `assets:precompile`. If [Editor rendering](docs/editor.md) is enabled, its peer dependencies must be available too.
563
690
 
564
- The build command preserves `emails.path`, `emails.extension`, `emails.ignore`, `standalone`, and email-only `vite` options.
691
+ The Ruby gem and npm package must stay on the same version. A protocol/version handshake catches mismatched installs and raises an actionable `ReactEmailRails::RenderError`.
565
692
 
566
- ### Renderer Verification
693
+ ### Verify the Renderer
567
694
 
568
- To confirm the renderer is ready before relying on it, run:
695
+ Run this before relying on the production renderer:
569
696
 
570
697
  ```sh
571
698
  bin/rails react_email_rails:verify
572
699
  ```
573
700
 
574
- It checks that the render command runs and that the npm package version matches the gem, then exits non-zero with an actionable message on failure. Wire it into CI or release steps to catch missing bundles or version drift before the first render.
701
+ It checks that the render command runs and that the npm package version matches the gem. It exits non-zero with an actionable message on failure, so it is safe to wire into CI or release steps.
575
702
 
576
- For programmatic checks (for example, a health endpoint), `ReactEmailRails.healthy?` returns a boolean. If you specifically want a check at boot, call it from your own initializer and scope it to the processes that send mail so others don't pay the cost:
703
+ For programmatic checks, `ReactEmailRails.healthy?` returns a boolean:
577
704
 
578
705
  ```ruby
579
706
  Rails.application.config.after_initialize do
@@ -583,13 +710,31 @@ Rails.application.config.after_initialize do
583
710
  end
584
711
  ```
585
712
 
713
+ If you check at boot, scope it to processes that send mail so the rest of the app does not pay the cost.
714
+
586
715
  ## Development
587
716
 
588
717
  See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, checks, formatting, and release verification.
589
718
 
719
+ The short version:
720
+
721
+ ```sh
722
+ bundle install
723
+ cd vite && pnpm install
724
+ ```
725
+
726
+ Run the core checks before opening a pull request:
727
+
728
+ ```sh
729
+ ruby scripts/check_version_sync.rb
730
+ bin/test
731
+ bin/lint
732
+ cd vite && pnpm run build
733
+ ```
734
+
590
735
  ## Contributing
591
736
 
592
- Bug reports and pull requests are welcome on GitHub. See [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.
737
+ Bug reports and pull requests are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request so the local checks and release expectations are clear.
593
738
 
594
739
  ## Security
595
740
 
@@ -597,4 +742,4 @@ Please report vulnerabilities privately. See [SECURITY.md](SECURITY.md) for deta
597
742
 
598
743
  ## License
599
744
 
600
- The gem and npm package are available as open source under the terms of the [MIT License](LICENSE.md).
745
+ The Ruby gem and npm package are available as open source under the terms of the [MIT License](LICENSE.md).
@@ -164,7 +164,6 @@ class ReactEmailRails::Generators::EmailGenerator < Rails::Generators::NamedBase
164
164
  )
165
165
  end
166
166
 
167
- # First capture-group match across an ordered list of patterns, or nil.
168
167
  def first_capture(source, *patterns)
169
168
  patterns.each do |pattern|
170
169
  match = source[pattern, 1]
@@ -13,8 +13,6 @@ module ReactEmailRails::ActionMailer
13
13
  self.react_email_use_instance_props = true
14
14
  end
15
15
 
16
- # Share props with every `react:` email this mailer and its subclasses render.
17
- # Mirrors inertia-rails `inertia_share`; `only`/`except`/`if`/`unless` go to `before_action`.
18
16
  def react_email_share(hash = nil, **props, &block)
19
17
  options = props.slice(*SHARED_FILTER_OPTIONS)
20
18
  data = hash || props.except(*SHARED_FILTER_OPTIONS)
@@ -25,36 +23,49 @@ module ReactEmailRails::ActionMailer
25
23
  end
26
24
  end
27
25
 
28
- # Share props from within an action, e.g. conditionally before calling `mail`.
29
26
  def react_email_share(hash = nil, **props, &block)
30
27
  react_email_append_shared(hash || props, block)
31
28
  end
32
29
 
33
30
  def mail(headers = {}, &block)
34
- return super unless headers.is_a?(Hash) && headers.key?(:react)
31
+ return super unless headers.is_a?(Hash)
32
+ return super if headers.empty? && @_mail_was_called
35
33
 
36
- headers = headers.dup
37
- react = headers.delete(:react)
38
- props = headers.delete(:props) if headers.key?(:props)
39
- deep_merge = headers.delete(:deep_merge) if headers.key?(:deep_merge)
34
+ react = headers.key?(:react) ? headers[:react] : compute_default(self.class.default[:react])
35
+ return super unless react
36
+
37
+ props = headers[:props]
38
+ deep_merge = headers[:deep_merge]
39
+ headers = headers.except(:react, :props, :deep_merge)
40
40
 
41
41
  component, resolved_props = ReactEmailRails::PropsResolver.new(self).resolve(react, props)
42
42
  resolved_props = ReactEmailRails::SharedProps.new(self).merge_into(
43
43
  resolved_props,
44
44
  deep_merge: react_email_deep_merge?(deep_merge),
45
45
  )
46
- render_options = ReactEmailRails.configuration.resolve_render_options(self)
47
- rendered = ReactEmailRails.render(component:, props: resolved_props, render_options:)
48
46
 
49
47
  super(headers) do |format|
48
+ rendered = react_email_render(component, resolved_props)
49
+
50
50
  format.html { rendered.html }
51
51
  format.text { rendered.text } if rendered.text.present?
52
+
52
53
  yield(format) if block
53
54
  end
54
55
  end
55
56
 
56
57
  private
57
58
 
59
+ def assign_headers_to_message(message, headers)
60
+ super(message, headers.except(:react, :props, :deep_merge))
61
+ end
62
+
63
+ def react_email_render(component, props)
64
+ props = ReactEmailRails::MailerContext.new(self).merge_into(props)
65
+ render_options = ReactEmailRails.configuration.resolve_render_options(self)
66
+ ReactEmailRails.render(component:, props:, render_options:)
67
+ end
68
+
58
69
  def react_email_append_shared(data, block)
59
70
  store = (@_react_email_shared ||= [])
60
71
  store << data.dup.freeze if data.present?
@@ -0,0 +1,40 @@
1
+ class ReactEmailRails::MailerContext
2
+ MESSAGE_FIELDS = [:subject, :to, :cc, :bcc, :from, :reply_to].freeze
3
+
4
+ def initialize(mailer)
5
+ @mailer = mailer
6
+ end
7
+
8
+ def merge_into(props)
9
+ serialized_props = props.as_json
10
+ return props unless serialized_props.is_a?(Hash)
11
+
12
+ to_h.merge(serialized_props)
13
+ end
14
+
15
+ def to_h
16
+ {
17
+ "mailer" => mailer_context,
18
+ "message" => message_context,
19
+ }
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader(:mailer)
25
+
26
+ def mailer_context
27
+ {
28
+ "mailer_name" => mailer.class.mailer_name,
29
+ "action_name" => mailer.action_name,
30
+ }
31
+ end
32
+
33
+ def message_context
34
+ message = mailer.message
35
+
36
+ MESSAGE_FIELDS.each_with_object({}) do |field, context|
37
+ context[field.to_s] = message.public_send(field)
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module ReactEmailRails
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.1"
3
3
  end
@@ -26,6 +26,7 @@ require_relative("react_email_rails/configuration")
26
26
  require_relative("react_email_rails/tasks")
27
27
  require_relative("react_email_rails/props_resolver")
28
28
  require_relative("react_email_rails/shared_props")
29
+ require_relative("react_email_rails/mailer_context")
29
30
  require_relative("react_email_rails/railtie")
30
31
 
31
32
  module ReactEmailRails
@@ -58,8 +59,7 @@ module ReactEmailRails
58
59
  perform(payload:, label: type, kind: "document", type:)
59
60
  end
60
61
 
61
- # Parse semantic HTML or Markdown into an editor document Hash using the renderer's
62
- # extensions. Pass exactly one of `html:` or `markdown:`.
62
+ # Returns an editor document Hash, built via the renderer's extensions. Pass exactly one of `html:`/`markdown:`.
63
63
  def parse(type:, html: nil, markdown: nil, context: {})
64
64
  payload = {
65
65
  kind: "parse",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react-email-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Supertape
@@ -153,6 +153,7 @@ files:
153
153
  - lib/react_email_rails.rb
154
154
  - lib/react_email_rails/action_mailer.rb
155
155
  - lib/react_email_rails/configuration.rb
156
+ - lib/react_email_rails/mailer_context.rb
156
157
  - lib/react_email_rails/props_resolver.rb
157
158
  - lib/react_email_rails/railtie.rb
158
159
  - lib/react_email_rails/render_error.rb