@aglyn/shared-util-email 1.0.0-beta.264 → 1.0.0-beta.266

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.
@@ -58,6 +58,13 @@ import { BRAND } from "@aglyn/shared-data-enums/aglyn";
58
58
  import { EMAIL_NODE_ROOT_ID } from "./email-render.js";
59
59
  import { RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES } from "./risk-notice-emails.js";
60
60
  import { retentionSystemEmailTemplates } from "./retention-emails.js";
61
+ import { welcomeEmailMergeValues } from "./welcome-email.js";
62
+ /** The welcome email's next steps, as a new workspace's owner gets them. */ const WELCOME_SAMPLES = welcomeEmailMergeValues({
63
+ orgName: 'Test Org',
64
+ slug: 'test-org',
65
+ consoleOrigin: SAMPLE_CONSOLE_ORIGIN,
66
+ docsOrigin: SAMPLE_DOCS_ORIGIN
67
+ });
61
68
  /**
62
69
  * Every system email Aglyn sends.
63
70
  *
@@ -127,7 +134,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
127
134
  {
128
135
  name: 'invite.role',
129
136
  description: 'Role the person is invited as',
130
- sample: 'editor'
137
+ sample: 'Editor'
131
138
  },
132
139
  {
133
140
  name: 'signInUrl',
@@ -139,18 +146,33 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
139
146
  defaultBody: [
140
147
  {
141
148
  block: 'text',
142
- text: "You've been invited to join {{org.name}} as {{invite.role}}.",
143
- variant: 'body'
149
+ text: 'Invitation · {{org.name}}',
150
+ variant: 'eyebrow'
144
151
  },
145
152
  {
146
153
  block: 'text',
147
- text: 'Sign in with this email address and accept the invite from ' + 'your dashboard.',
154
+ text: 'Join {{org.name}} on {{brand.productName}}',
155
+ variant: 'heading'
156
+ },
157
+ {
158
+ block: 'text',
159
+ text: 'You\'ve been invited to join {{org.name}} as {{invite.role}}. Sign in with this email address and the invitation is waiting on your dashboard.',
148
160
  variant: 'body'
149
161
  },
162
+ {
163
+ block: 'text',
164
+ text: 'Workspace: {{org.name}}\nYour role: {{invite.role}}',
165
+ variant: 'details'
166
+ },
150
167
  {
151
168
  block: 'button',
152
- label: 'Sign in',
169
+ label: 'Accept the invitation',
153
170
  href: '{{signInUrl}}'
171
+ },
172
+ {
173
+ block: 'text',
174
+ text: 'Not expecting this? You can ignore it. Nothing happens unless you accept.',
175
+ variant: 'caption'
154
176
  }
155
177
  ],
156
178
  footerReason: 'You’re receiving this because someone invited you to join ' + '{{org.name}} on {{brand.productName}}.',
@@ -181,6 +203,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
181
203
  ],
182
204
  // Mirrors the fallback text in invites/route.ts.
183
205
  defaultBody: [
206
+ {
207
+ block: 'text',
208
+ text: 'Ownership transfer · {{org.name}}',
209
+ variant: 'eyebrow'
210
+ },
184
211
  {
185
212
  block: 'text',
186
213
  text: '{{org.name}} is being handed to you',
@@ -188,18 +215,23 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
188
215
  },
189
216
  {
190
217
  block: 'text',
191
- text: "You've been invited to take over {{org.name}} as its owner. " + 'Accepting makes you the owner of the workspace and every site ' + 'in it. {{handoff.previousOwner}}',
218
+ text: 'You\'ve been invited to take over {{org.name}} as its owner. The owner holds the workspace, every site in it, and its billing. {{handoff.previousOwner}}',
192
219
  variant: 'body'
193
220
  },
194
221
  {
195
222
  block: 'text',
196
- text: 'Sign in with this email address and accept the invitation ' + 'from your dashboard. Nothing changes until you accept.',
197
- variant: 'body'
223
+ text: 'Workspace: {{org.name}}\nYour role: Owner',
224
+ variant: 'details'
198
225
  },
199
226
  {
200
227
  block: 'button',
201
- label: 'Sign in',
228
+ label: 'Review and accept',
202
229
  href: '{{signInUrl}}'
230
+ },
231
+ {
232
+ block: 'text',
233
+ text: 'Nothing changes until you accept. Sign in with this email address to see the invitation.',
234
+ variant: 'caption'
203
235
  }
204
236
  ],
205
237
  footerReason: 'You’re receiving this because someone invited you to take over ' + '{{org.name}} on {{brand.productName}}.',
@@ -235,6 +267,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
235
267
  ],
236
268
  // Mirrors the fallback text in /api/admin/org-upgrade-proposal.
237
269
  defaultBody: [
270
+ {
271
+ block: 'text',
272
+ text: '{{org.name}}',
273
+ variant: 'eyebrow'
274
+ },
238
275
  {
239
276
  block: 'text',
240
277
  text: 'The {{plan.name}} plan, proposed for {{org.name}}',
@@ -242,7 +279,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
242
279
  },
243
280
  {
244
281
  block: 'text',
245
- text: 'Your {{brand.productName}} team proposed moving {{org.name}} to ' + 'the {{plan.name}} plan. When you are ready, start the ' + 'subscription from Billing, where the plan is already selected.',
282
+ text: 'Your {{brand.productName}} team proposed moving {{org.name}} to the {{plan.name}} plan.',
246
283
  variant: 'body'
247
284
  },
248
285
  {
@@ -250,10 +287,20 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
250
287
  text: '{{proposal.note}}',
251
288
  variant: 'body'
252
289
  },
290
+ {
291
+ block: 'text',
292
+ text: 'When you are ready, start the subscription from Billing. The plan is already selected there, beside the others so you can compare them first.',
293
+ variant: 'body'
294
+ },
253
295
  {
254
296
  block: 'button',
255
- label: 'Review the plan',
297
+ label: 'Review the {{plan.name}} plan',
256
298
  href: '{{billingUrl}}'
299
+ },
300
+ {
301
+ block: 'text',
302
+ text: 'Nothing changes until you start the subscription.',
303
+ variant: 'caption'
257
304
  }
258
305
  ],
259
306
  footerReason: 'You’re receiving this because you own {{org.name}} on ' + '{{brand.productName}} and its team proposed a plan for it.',
@@ -285,24 +332,49 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
285
332
  name: 'usage.summary',
286
333
  description: 'Pre-formatted usage lines',
287
334
  sample: 'Plan: Starter\nPage views: 12,400\n' + 'Metered usage beyond your plan: none, so nothing extra is billed for it.'
335
+ },
336
+ {
337
+ name: 'billingUrl',
338
+ description: 'The workspace Billing page',
339
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing`
288
340
  }
289
341
  ],
290
342
  // Mirrors the summary lines assembled in usage-email/route.ts.
291
343
  defaultBody: [
292
344
  {
293
345
  block: 'text',
294
- text: 'Usage summary for {{org.name}}',
346
+ text: '{{month.label}} · {{org.name}}',
347
+ variant: 'eyebrow'
348
+ },
349
+ {
350
+ block: 'text',
351
+ text: 'Your usage for {{month.label}}',
295
352
  variant: 'heading'
296
353
  },
297
354
  {
298
355
  block: 'text',
299
- text: 'Here is how {{org.name}} used {{brand.productName}} in {{month.label}}.',
356
+ text: 'Here is how {{org.name}} used {{brand.productName}} in {{month.label}}: your plan, storage, page views and anything metered beyond the plan.',
300
357
  variant: 'body'
301
358
  },
302
359
  {
303
360
  block: 'text',
304
361
  text: '{{usage.summary}}',
362
+ variant: 'details'
363
+ },
364
+ {
365
+ block: 'text',
366
+ text: 'Billing shows the full meters beside each plan limit, and the invoices for every month.',
305
367
  variant: 'body'
368
+ },
369
+ {
370
+ block: 'button',
371
+ label: 'Open billing',
372
+ href: '{{billingUrl}}'
373
+ },
374
+ {
375
+ block: 'text',
376
+ text: 'Usage that goes over your plan is billed with the next invoice. A larger plan includes more, and you can compare them from Billing.',
377
+ variant: 'caption'
306
378
  }
307
379
  ],
308
380
  footerReason: 'You’re receiving this monthly summary because you manage ' + '{{org.name}} on {{brand.productName}}.',
@@ -323,7 +395,12 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
323
395
  {
324
396
  name: 'orgs.list',
325
397
  description: 'The organizations, one per line',
326
- sample: '- Test Org (org_123), requested 2026-07-01'
398
+ sample: 'Test Org (org_123) — requested 2026-07-01\nNorth Bakery (org_456) — requested 2026-07-02'
399
+ },
400
+ {
401
+ name: 'healthUrl',
402
+ description: 'Staff → Health, where pending erasures can be run',
403
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/health`
327
404
  }
328
405
  ],
329
406
  // Mirrors the staff-alert text in audit-archive/route.ts. It reports
@@ -332,13 +409,33 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
332
409
  defaultBody: [
333
410
  {
334
411
  block: 'text',
335
- text: 'These workspaces are past their 7-day erasure hold. The nightly ' + 'erasure job erases them at 04:00 UTC, five a run and oldest ' + 'first, and keeps no copy, so nothing is needed from you. A ' + 'workspace still listed here tomorrow either failed to erase, ' + 'which raises its own "could not be erased" alert, or is waiting ' + 'behind a longer queue. Pending erasures on Staff → Health can ' + 'run the due ones sooner.',
412
+ text: 'Staff · data erasure',
413
+ variant: 'eyebrow'
414
+ },
415
+ {
416
+ block: 'text',
417
+ text: '{{count}} erasure request(s) past the hold',
418
+ variant: 'heading'
419
+ },
420
+ {
421
+ block: 'text',
422
+ text: 'These workspaces are past their 7-day erasure hold. The nightly erasure job erases them at 04:00 UTC, five a run and oldest first, and keeps no copy, so nothing is needed from you.',
336
423
  variant: 'body'
337
424
  },
338
425
  {
339
426
  block: 'text',
340
427
  text: '{{orgs.list}}',
428
+ variant: 'details'
429
+ },
430
+ {
431
+ block: 'text',
432
+ text: 'A workspace still listed tomorrow either failed to erase, which raises its own "could not be erased" alert, or is waiting behind a longer queue. Pending erasures on Staff → Health can run the due ones sooner.',
341
433
  variant: 'body'
434
+ },
435
+ {
436
+ block: 'button',
437
+ label: 'Open Staff → Health',
438
+ href: '{{healthUrl}}'
342
439
  }
343
440
  ],
344
441
  footerReason: 'You’re receiving this because this address gets ' + '{{brand.productName}}’s staff alerts.',
@@ -365,29 +462,49 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
365
462
  name: 'consoleUrl',
366
463
  description: 'Console dashboard URL',
367
464
  sample: SAMPLE_CONSOLE_ORIGIN
465
+ },
466
+ {
467
+ name: 'welcome.intro',
468
+ description: 'What is ready, and what to do first, for how the workspace started',
469
+ sample: WELCOME_SAMPLES['welcome.intro']
470
+ },
471
+ {
472
+ name: 'welcome.steps',
473
+ description: 'The next steps, one per line, each "Step — link"',
474
+ sample: WELCOME_SAMPLES['welcome.steps']
368
475
  }
369
476
  ],
370
477
  // Mirrors the fallbackText in orgs/create/route.ts.
371
478
  defaultBody: [
372
479
  {
373
480
  block: 'text',
374
- text: 'Welcome to {{brand.productName}}',
481
+ text: '{{org.name}}',
482
+ variant: 'eyebrow'
483
+ },
484
+ {
485
+ block: 'text',
486
+ text: 'Welcome to {{brand.productName}}, {{name}}',
375
487
  variant: 'heading'
376
488
  },
377
489
  {
378
490
  block: 'text',
379
- text: 'Hi {{name}}, thanks for creating {{org.name}}. Your workspace ' + 'is ready.',
491
+ text: '{{welcome.intro}}',
380
492
  variant: 'body'
381
493
  },
382
494
  {
383
495
  block: 'text',
384
- text: 'From your dashboard you can add a site, invite your team, and ' + 'start building.',
385
- variant: 'body'
496
+ text: '{{welcome.steps}}',
497
+ variant: 'links'
386
498
  },
387
499
  {
388
500
  block: 'button',
389
- label: 'Open your dashboard',
501
+ label: 'Open {{org.name}}',
390
502
  href: '{{consoleUrl}}'
503
+ },
504
+ {
505
+ block: 'text',
506
+ text: 'Questions as you build? The guides answer most of them, and support is a click away: {{brand.supportUrl}}',
507
+ variant: 'caption'
391
508
  }
392
509
  ],
393
510
  footerReason: 'You’re receiving this because you created an organization on ' + '{{brand.productName}}.',
@@ -408,7 +525,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
408
525
  {
409
526
  name: 'member.role',
410
527
  description: 'Role they were given',
411
- sample: 'editor'
528
+ sample: 'Editor'
412
529
  },
413
530
  {
414
531
  name: 'signInUrl',
@@ -420,18 +537,33 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
420
537
  defaultBody: [
421
538
  {
422
539
  block: 'text',
423
- text: 'You were added to {{org.name}} as {{member.role}}.',
424
- variant: 'body'
540
+ text: '{{org.name}}',
541
+ variant: 'eyebrow'
425
542
  },
426
543
  {
427
544
  block: 'text',
428
- text: 'Sign in to switch to it from your dashboard.',
545
+ text: 'You’re in {{org.name}}',
546
+ variant: 'heading'
547
+ },
548
+ {
549
+ block: 'text',
550
+ text: 'You were added to {{org.name}} as {{member.role}}. Sign in and pick it from the workspace menu to see its sites.',
429
551
  variant: 'body'
430
552
  },
553
+ {
554
+ block: 'text',
555
+ text: 'Workspace: {{org.name}}\nYour role: {{member.role}}',
556
+ variant: 'details'
557
+ },
431
558
  {
432
559
  block: 'button',
433
- label: 'Open {{brand.productName}}',
560
+ label: 'Open {{org.name}}',
434
561
  href: '{{signInUrl}}'
562
+ },
563
+ {
564
+ block: 'text',
565
+ text: 'Not expecting this? Ask whoever runs {{org.name}}, or contact support: {{brand.supportUrl}}',
566
+ variant: 'caption'
435
567
  }
436
568
  ],
437
569
  footerReason: 'You’re receiving this because you were added to {{org.name}} ' + 'on {{brand.productName}}.',
@@ -452,6 +584,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
452
584
  ],
453
585
  // Mirrors the fallbackText in admin/run-erasures/route.ts.
454
586
  defaultBody: [
587
+ {
588
+ block: 'text',
589
+ text: 'Data erasure · {{org.name}}',
590
+ variant: 'eyebrow'
591
+ },
455
592
  {
456
593
  block: 'text',
457
594
  text: 'Your data has been erased',
@@ -459,13 +596,23 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
459
596
  },
460
597
  {
461
598
  block: 'text',
462
- text: '{{org.name}} and all of its data have been permanently erased ' + 'from {{brand.productName}}, as requested.',
599
+ text: '{{org.name}} and all of its data have been permanently erased from {{brand.productName}}, as you asked. This is complete and cannot be undone.',
463
600
  variant: 'body'
464
601
  },
465
602
  {
466
603
  block: 'text',
467
- text: 'This is complete and cannot be undone.',
604
+ text: 'Workspace: {{org.name}}\nStatus: Erased',
605
+ variant: 'details'
606
+ },
607
+ {
608
+ block: 'text',
609
+ text: 'Nothing more is needed from you. Your sign-in stays, so you can start a new workspace any time.',
468
610
  variant: 'body'
611
+ },
612
+ {
613
+ block: 'text',
614
+ text: 'Questions about the erasure? Contact support: {{brand.supportUrl}}',
615
+ variant: 'caption'
469
616
  }
470
617
  ],
471
618
  footerReason: 'You’re receiving this because you asked {{brand.productName}} ' + 'to erase {{org.name}}’s data.',
@@ -482,24 +629,49 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
482
629
  name: 'org.name',
483
630
  description: 'The organization to be erased',
484
631
  sample: 'Test Org'
632
+ },
633
+ {
634
+ name: 'erasure.date',
635
+ description: 'The day the 7-day hold ends and erasure runs',
636
+ sample: 'July 8, 2026'
485
637
  }
486
638
  ],
487
639
  // Mirrors the fallbackText in admin/erasure-request/route.ts.
488
640
  defaultBody: [
489
641
  {
490
642
  block: 'text',
491
- text: 'Erasure request received',
643
+ text: 'Data erasure · {{org.name}}',
644
+ variant: 'eyebrow'
645
+ },
646
+ {
647
+ block: 'text',
648
+ text: 'Your erasure request is recorded',
492
649
  variant: 'heading'
493
650
  },
494
651
  {
495
652
  block: 'text',
496
- text: 'We have recorded a request to erase {{org.name}} and all of ' + 'its data from {{brand.productName}}.',
653
+ text: 'We have recorded a request to erase {{org.name}} and all of its data from {{brand.productName}}: every site, form submission, order, file and member.',
497
654
  variant: 'body'
498
655
  },
499
656
  {
500
657
  block: 'text',
501
- text: 'Deletion is permanent and happens after a 7-day hold. If this ' + 'was not intended, contact support before then to cancel.',
658
+ text: 'Workspace: {{org.name}}\nErased on: {{erasure.date}}',
659
+ variant: 'details'
660
+ },
661
+ {
662
+ block: 'text',
663
+ text: 'Erasure is permanent. It waits out a 7-day hold first, so if this was not intended, contact support before {{erasure.date}} and we will cancel it.',
502
664
  variant: 'body'
665
+ },
666
+ {
667
+ block: 'button',
668
+ label: 'Contact support',
669
+ href: '{{brand.supportUrl}}'
670
+ },
671
+ {
672
+ block: 'text',
673
+ text: 'Want a copy of anything first? Export it from the workspace before the hold ends.',
674
+ variant: 'caption'
503
675
  }
504
676
  ],
505
677
  footerReason: 'You’re receiving this because you own {{org.name}} on ' + '{{brand.productName}}.',
@@ -529,6 +701,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
529
701
  ],
530
702
  // Mirrors the fallbackText in _lib/password-admin.ts.
531
703
  defaultBody: [
704
+ {
705
+ block: 'text',
706
+ text: 'Account security',
707
+ variant: 'eyebrow'
708
+ },
532
709
  {
533
710
  block: 'text',
534
711
  text: 'Reset your password',
@@ -536,7 +713,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
536
713
  },
537
714
  {
538
715
  block: 'text',
539
- text: '{{actor.name}} started a password reset for your {{brand.productName}} ' + 'account. Choose a new password here:',
716
+ text: '{{actor.name}} started a password reset for your {{brand.productName}} account. Choose a new password with the button below.',
540
717
  variant: 'body'
541
718
  },
542
719
  {
@@ -546,7 +723,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
546
723
  },
547
724
  {
548
725
  block: 'text',
549
- text: 'The link expires shortly. If you were not expecting this, you ' + 'can ignore this email — your password stays as it is.',
726
+ text: 'The link works once and expires shortly. If you were not expecting this, ignore this email and your password stays as it is.',
550
727
  variant: 'caption'
551
728
  }
552
729
  ],
@@ -573,6 +750,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
573
750
  ],
574
751
  // Mirrors the fallbackText in _lib/password-admin.ts.
575
752
  defaultBody: [
753
+ {
754
+ block: 'text',
755
+ text: 'Account security',
756
+ variant: 'eyebrow'
757
+ },
576
758
  {
577
759
  block: 'text',
578
760
  text: 'Your password was changed',
@@ -580,9 +762,14 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
580
762
  },
581
763
  {
582
764
  block: 'text',
583
- text: '{{actor.name}} set a new password on your {{brand.productName}} ' + 'account. You have ' + 'been signed out everywhere and will need the new password to ' + 'sign back in.',
765
+ text: '{{actor.name}} set a new password on your {{brand.productName}} account and signed you out everywhere. Sign back in with the new password.',
584
766
  variant: 'body'
585
767
  },
768
+ {
769
+ block: 'text',
770
+ text: 'Changed by: {{actor.name}}',
771
+ variant: 'details'
772
+ },
586
773
  {
587
774
  block: 'button',
588
775
  label: 'Sign in',
@@ -590,7 +777,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
590
777
  },
591
778
  {
592
779
  block: 'text',
593
- text: 'If you did not expect this, contact whoever administers your ' + 'account straight away.',
780
+ text: 'If you did not expect this, contact whoever administers your account straight away, or support: {{brand.supportUrl}}',
594
781
  variant: 'caption'
595
782
  }
596
783
  ],
@@ -638,50 +825,33 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
638
825
  defaultBody: [
639
826
  {
640
827
  block: 'text',
641
- text: 'New device sign-in',
642
- variant: 'heading'
643
- },
644
- {
645
- block: 'text',
646
- text: 'Your {{brand.productName}} account was just signed in to from a device it has ' + 'not used before.',
647
- variant: 'body'
828
+ text: 'Security alert',
829
+ variant: 'eyebrow'
648
830
  },
649
831
  {
650
832
  block: 'text',
651
- text: 'Device: {{device.name}}',
652
- variant: 'body'
833
+ text: 'New device sign-in',
834
+ variant: 'heading'
653
835
  },
654
836
  {
655
837
  block: 'text',
656
- text: 'Location: {{device.location}}',
838
+ text: 'Your {{brand.productName}} account was just signed in to from a device it has not used before.',
657
839
  variant: 'body'
658
840
  },
659
841
  {
660
842
  block: 'text',
661
- text: 'IP address: {{device.ip}}',
662
- variant: 'body'
843
+ text: 'Device: {{device.name}}\nLocation: {{device.location}}\nIP address: {{device.ip}}\nWhen: {{device.time}}',
844
+ variant: 'details'
663
845
  },
664
846
  {
665
847
  block: 'text',
666
- text: 'When: {{device.time}}',
848
+ text: 'If this was you, there is nothing to do. If it was not, sign this device out from Recent sign-ins and change your password right away.',
667
849
  variant: 'body'
668
850
  },
669
851
  {
670
- // AGL-1959. The button used to say "Review account security" and
671
- // land on the account page's DEFAULT tab, which offered a password
672
- // change and nothing about the device the mail is about. AGL-665
673
- // asked for this: "'Manage your devices' has to land somewhere that
674
- // can list and revoke sessions, or the alert tells you something is
675
- // wrong and offers no way to act on it — which is worse than sending
676
- // nothing."
677
852
  block: 'button',
678
- label: 'Manage your devices',
853
+ label: 'Review your devices',
679
854
  href: '{{accountSecurityUrl}}'
680
- },
681
- {
682
- block: 'text',
683
- text: 'If this was you, no action is needed. If it was not, sign this ' + 'device out from Recent sign-ins and change your password right ' + 'away.',
684
- variant: 'caption'
685
855
  }
686
856
  ],
687
857
  footerReason: 'You’re receiving this because your {{brand.productName}} ' + 'account signed in from a new device.',
@@ -712,6 +882,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
712
882
  ],
713
883
  // Mirrors the fallbackText in _lib/security-alerts.ts.
714
884
  defaultBody: [
885
+ {
886
+ block: 'text',
887
+ text: 'Security alert',
888
+ variant: 'eyebrow'
889
+ },
715
890
  {
716
891
  block: 'text',
717
892
  text: 'New passkey added',
@@ -719,23 +894,23 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
719
894
  },
720
895
  {
721
896
  block: 'text',
722
- text: 'A passkey ("{{passkey.label}}") was just added to your {{brand.productName}} ' + 'account. It can be used to sign in without your password.',
897
+ text: 'A passkey was just added to your {{brand.productName}} account. It can sign you in without your password.',
723
898
  variant: 'body'
724
899
  },
725
900
  {
726
901
  block: 'text',
727
- text: 'When: {{device.time}}',
902
+ text: 'Passkey: {{passkey.label}}\nWhen: {{device.time}}',
903
+ variant: 'details'
904
+ },
905
+ {
906
+ block: 'text',
907
+ text: 'If you added it, there is nothing to do. If you did not, remove it and change your password right away.',
728
908
  variant: 'body'
729
909
  },
730
910
  {
731
911
  block: 'button',
732
912
  label: 'Review account security',
733
913
  href: '{{accountSecurityUrl}}'
734
- },
735
- {
736
- block: 'text',
737
- text: 'If you did not add this passkey, change your password from ' + 'Manage account right away.',
738
- variant: 'caption'
739
914
  }
740
915
  ],
741
916
  footerReason: 'You’re receiving this because a passkey was added to your ' + '{{brand.productName}} account.',
@@ -767,6 +942,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
767
942
  // Mirrors the fallbackText in the route, so the designed and undesigned
768
943
  // versions say the same thing.
769
944
  defaultBody: [
945
+ {
946
+ block: 'text',
947
+ text: 'Account security',
948
+ variant: 'eyebrow'
949
+ },
770
950
  {
771
951
  block: 'text',
772
952
  text: 'Reset your password',
@@ -774,7 +954,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
774
954
  },
775
955
  {
776
956
  block: 'text',
777
- text: 'Someone asked to reset the password for your {{brand.productName}} account. ' + 'Choose a new one here:',
957
+ text: 'Someone asked to reset the password for your {{brand.productName}} account. If it was you, choose a new one with the button below.',
778
958
  variant: 'body'
779
959
  },
780
960
  {
@@ -784,7 +964,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
784
964
  },
785
965
  {
786
966
  block: 'text',
787
- text: 'The link expires shortly. If this was not you, you can ignore ' + 'this email — your password stays as it is.',
967
+ text: 'The link works once and expires shortly. If this was not you, ignore this email and your password stays as it is.',
788
968
  variant: 'caption'
789
969
  }
790
970
  ],
@@ -805,6 +985,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
805
985
  }
806
986
  ],
807
987
  defaultBody: [
988
+ {
989
+ block: 'text',
990
+ text: 'One last step',
991
+ variant: 'eyebrow'
992
+ },
808
993
  {
809
994
  block: 'text',
810
995
  text: 'Confirm your email',
@@ -812,7 +997,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
812
997
  },
813
998
  {
814
999
  block: 'text',
815
- text: 'Confirm this address to finish setting up your {{brand.productName}} account:',
1000
+ text: 'Confirm this address to finish setting up your {{brand.productName}} account. It keeps your account secure, and it is where we tell you about your sites: new form submissions, orders and bookings.',
816
1001
  variant: 'body'
817
1002
  },
818
1003
  {
@@ -822,7 +1007,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
822
1007
  },
823
1008
  {
824
1009
  block: 'text',
825
- text: 'If you did not create an {{brand.productName}} account, you can ignore this ' + 'email.',
1010
+ text: 'If you did not sign up for {{brand.productName}}, you can ignore this email.',
826
1011
  variant: 'caption'
827
1012
  }
828
1013
  ],
@@ -850,6 +1035,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
850
1035
  ],
851
1036
  // Mirrors the fallbackText in the route.
852
1037
  defaultBody: [
1038
+ {
1039
+ block: 'text',
1040
+ text: 'Account security',
1041
+ variant: 'eyebrow'
1042
+ },
853
1043
  {
854
1044
  block: 'text',
855
1045
  text: 'Confirm this email address',
@@ -857,7 +1047,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
857
1047
  },
858
1048
  {
859
1049
  block: 'text',
860
- text: 'Confirm this address so you can use it with your ' + '{{brand.productName}} account:',
1050
+ text: 'Confirm this address to add it to your {{brand.productName}} account. Once it is confirmed you can sign in with it and choose it for your email.',
861
1051
  variant: 'body'
862
1052
  },
863
1053
  {
@@ -867,7 +1057,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
867
1057
  },
868
1058
  {
869
1059
  block: 'text',
870
- text: 'If you did not ask to add this address, you can ignore this ' + 'email — nothing has changed and the address has not been added ' + 'to any account.',
1060
+ text: 'If you did not ask to add this address, ignore this email. Nothing has changed, and the address has not been added to any account.',
871
1061
  variant: 'caption'
872
1062
  }
873
1063
  ],
@@ -925,7 +1115,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
925
1115
  },
926
1116
  {
927
1117
  block: 'text',
928
- text: '{{sender.name}}',
1118
+ text: '{{sender.name}}\n{{brand.productName}}',
929
1119
  variant: 'body'
930
1120
  },
931
1121
  {
@@ -964,6 +1154,21 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
964
1154
  description: 'What the email alone carries, one line each, when there is any: ' + 'a form submission’s answers',
965
1155
  sample: 'Name: Jane Doe\nEmail: jane@example.com\nMessage: Do you deliver on Saturdays?'
966
1156
  },
1157
+ {
1158
+ name: 'notification.context',
1159
+ description: 'The site and workspace it is about, when it is about one',
1160
+ sample: 'Copper Kettle Catering · Test Org'
1161
+ },
1162
+ {
1163
+ name: 'notification.action',
1164
+ description: 'What the button opens: "View submission", "View order", or "Open in" the product',
1165
+ sample: 'View submission'
1166
+ },
1167
+ {
1168
+ name: 'notification.replyNote',
1169
+ description: 'Who a reply reaches, when it reaches the person who wrote in',
1170
+ sample: 'Reply to this email to answer maria.delgado@example.com.'
1171
+ },
967
1172
  {
968
1173
  name: 'notification.url',
969
1174
  description: 'Where the notification opens in the console',
@@ -976,6 +1181,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
976
1181
  }
977
1182
  ],
978
1183
  defaultBody: [
1184
+ {
1185
+ block: 'text',
1186
+ text: '{{notification.context}}',
1187
+ variant: 'eyebrow'
1188
+ },
979
1189
  {
980
1190
  block: 'text',
981
1191
  text: '{{notification.title}}',
@@ -989,13 +1199,18 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
989
1199
  {
990
1200
  block: 'text',
991
1201
  text: '{{notification.details}}',
992
- variant: 'body'
1202
+ variant: 'details'
993
1203
  },
994
1204
  {
995
1205
  block: 'button',
996
- label: 'Open in {{brand.productName}}',
1206
+ label: '{{notification.action}}',
997
1207
  href: '{{notification.url}}'
998
1208
  },
1209
+ {
1210
+ block: 'text',
1211
+ text: '{{notification.replyNote}}',
1212
+ variant: 'caption'
1213
+ },
999
1214
  {
1000
1215
  block: 'text',
1001
1216
  text: 'Change what you are emailed about: {{settingsUrl}}',
@@ -1021,11 +1236,26 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1021
1236
  name: 'alert.body',
1022
1237
  description: 'The alert as its sender wrote it',
1023
1238
  sample: 'Free-tier AI spend for 2026-09-28 (UTC) is at $40.00 of the $50.00 ceiling.'
1239
+ },
1240
+ {
1241
+ name: 'alert.url',
1242
+ description: 'Where the alert is handled; the staff console when the sender names nowhere',
1243
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/lockdown`
1244
+ },
1245
+ {
1246
+ name: 'alert.urlLabel',
1247
+ description: 'The button’s words for that page',
1248
+ sample: 'Open Staff → Lockdown'
1024
1249
  }
1025
1250
  ],
1026
1251
  // The subject heads the body (AGL-3432): a reader who skips the
1027
1252
  // subject line still sees what the alert is about.
1028
1253
  defaultBody: [
1254
+ {
1255
+ block: 'text',
1256
+ text: 'Staff alert',
1257
+ variant: 'eyebrow'
1258
+ },
1029
1259
  {
1030
1260
  block: 'text',
1031
1261
  text: '{{alert.subject}}',
@@ -1035,6 +1265,16 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1035
1265
  block: 'text',
1036
1266
  text: '{{alert.body}}',
1037
1267
  variant: 'body'
1268
+ },
1269
+ {
1270
+ block: 'button',
1271
+ label: '{{alert.urlLabel}}',
1272
+ href: '{{alert.url}}'
1273
+ },
1274
+ {
1275
+ block: 'text',
1276
+ text: 'Sent to the staff alert inbox. Every alert is also on Staff → Overview.',
1277
+ variant: 'caption'
1038
1278
  }
1039
1279
  ],
1040
1280
  footerReason: 'You’re receiving this because this address gets ' + '{{brand.productName}}’s staff alerts.',
@@ -1061,9 +1301,29 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1061
1301
  name: 'alert.url',
1062
1302
  description: 'The item in the staff console',
1063
1303
  sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/abuse-reports`
1304
+ },
1305
+ {
1306
+ name: 'alert.eyebrow',
1307
+ description: 'The alert’s level and area',
1308
+ sample: 'Must know · Payments & payouts'
1309
+ },
1310
+ {
1311
+ name: 'alert.details',
1312
+ description: 'Which alert, which workspace or site, and when, as "Label: value" lines',
1313
+ sample: 'Alert: Card testing\nLevel: Must know\nSite id: host_123\nRaised: 2026-09-28 14:03 UTC'
1314
+ },
1315
+ {
1316
+ name: 'settingsUrl',
1317
+ description: 'Staff → Operator alerts',
1318
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/operator-alerts`
1064
1319
  }
1065
1320
  ],
1066
1321
  defaultBody: [
1322
+ {
1323
+ block: 'text',
1324
+ text: '{{alert.eyebrow}}',
1325
+ variant: 'eyebrow'
1326
+ },
1067
1327
  {
1068
1328
  block: 'text',
1069
1329
  text: '{{alert.title}}',
@@ -1074,10 +1334,20 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1074
1334
  text: '{{alert.body}}',
1075
1335
  variant: 'body'
1076
1336
  },
1337
+ {
1338
+ block: 'text',
1339
+ text: '{{alert.details}}',
1340
+ variant: 'details'
1341
+ },
1077
1342
  {
1078
1343
  block: 'button',
1079
1344
  label: 'Review it',
1080
1345
  href: '{{alert.url}}'
1346
+ },
1347
+ {
1348
+ block: 'text',
1349
+ text: 'Choose which alerts email you, and which wait for the daily digest, on Staff → Operator alerts: {{settingsUrl}}',
1350
+ variant: 'caption'
1081
1351
  }
1082
1352
  ],
1083
1353
  footerReason: 'You’re receiving this because this address gets ' + '{{brand.productName}}’s operator alerts.',
@@ -1117,11 +1387,21 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1117
1387
  }
1118
1388
  ],
1119
1389
  defaultBody: [
1390
+ {
1391
+ block: 'text',
1392
+ text: 'Daily digest · {{digest.date}}',
1393
+ variant: 'eyebrow'
1394
+ },
1120
1395
  {
1121
1396
  block: 'text',
1122
1397
  text: '{{digest.title}}',
1123
1398
  variant: 'heading'
1124
1399
  },
1400
+ {
1401
+ block: 'text',
1402
+ text: 'The routine alerts from the last day, batched so they arrive together. None of them needed you right away.',
1403
+ variant: 'body'
1404
+ },
1125
1405
  {
1126
1406
  block: 'text',
1127
1407
  text: '{{digest.body}}',
@@ -1129,8 +1409,13 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1129
1409
  },
1130
1410
  {
1131
1411
  block: 'button',
1132
- label: 'Open the staff console',
1412
+ label: 'Open operator alerts',
1133
1413
  href: '{{digest.url}}'
1414
+ },
1415
+ {
1416
+ block: 'text',
1417
+ text: 'Choose which alerts wait for this digest on Staff → Operator alerts.',
1418
+ variant: 'caption'
1134
1419
  }
1135
1420
  ],
1136
1421
  footerReason: 'You’re receiving this because this address gets ' + '{{brand.productName}}’s operator alerts.',
@@ -1172,23 +1457,58 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1172
1457
  name: 'org.name',
1173
1458
  description: 'The organization the ticket is from',
1174
1459
  sample: 'Test Org'
1460
+ },
1461
+ {
1462
+ name: 'ticket.opening',
1463
+ description: 'Who opened or replied, as one sentence',
1464
+ sample: 'Test Org opened a support ticket.'
1465
+ },
1466
+ {
1467
+ name: 'ticket.message',
1468
+ description: 'What the customer wrote',
1469
+ sample: 'We added the TXT record yesterday and the domain still says pending.'
1470
+ },
1471
+ {
1472
+ name: 'ticket.details',
1473
+ description: 'The workspace, sender, subject and ticket id as "Label: value" lines',
1474
+ sample: 'Workspace: Test Org\nFrom: owner@example.com\nSubject: Domain will not verify\nTicket id: tkt_123'
1175
1475
  }
1176
1476
  ],
1177
1477
  defaultBody: [
1178
1478
  {
1179
1479
  block: 'text',
1180
- text: '{{manager.name}},',
1480
+ text: '{{ticket.heading}} · {{org.name}}',
1481
+ variant: 'eyebrow'
1482
+ },
1483
+ {
1484
+ block: 'text',
1485
+ text: '{{ticket.subject}}',
1486
+ variant: 'heading'
1487
+ },
1488
+ {
1489
+ block: 'text',
1490
+ text: '{{manager.name}}, {{ticket.opening}} You are its success manager, so it is copied to you.',
1181
1491
  variant: 'body'
1182
1492
  },
1183
1493
  {
1184
1494
  block: 'text',
1185
- text: '{{ticket.body}}',
1495
+ text: '{{ticket.details}}',
1496
+ variant: 'details'
1497
+ },
1498
+ {
1499
+ block: 'text',
1500
+ text: '{{ticket.message}}',
1186
1501
  variant: 'body'
1187
1502
  },
1188
1503
  {
1189
1504
  block: 'button',
1190
1505
  label: 'Open the ticket',
1191
1506
  href: '{{ticket.url}}'
1507
+ },
1508
+ {
1509
+ block: 'text',
1510
+ text: 'Answer from Staff → Support so the reply is threaded on the ticket and the customer sees it in their console.',
1511
+ variant: 'caption'
1192
1512
  }
1193
1513
  ],
1194
1514
  footerReason: 'You’re receiving this because you are the success manager for ' + '{{org.name}} on {{brand.productName}}.',
@@ -1204,22 +1524,52 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1204
1524
  {
1205
1525
  name: 'notice.subject',
1206
1526
  description: 'The notice, in one line',
1207
- sample: 'Test Org has used 80% of this month’s emails'
1527
+ sample: 'Sequences paused your mailbox avery@example.com'
1208
1528
  },
1209
1529
  {
1210
1530
  name: 'notice.body',
1211
1531
  description: 'The notice as its sender wrote it',
1212
- sample: 'Test Org has sent 8,000 of its 10,000 emails this month.'
1532
+ sample: 'Sequences paused the mailbox Avery Quinn <avery@example.com>.\n\nSequences paused it after 3 bounces in a row.'
1213
1533
  },
1214
1534
  {
1215
1535
  name: 'org.name',
1216
1536
  description: 'The workspace the notice is about',
1217
1537
  sample: 'Test Org'
1538
+ },
1539
+ {
1540
+ name: 'notice.lead',
1541
+ description: 'What happened and what to do, without the link',
1542
+ sample: 'Sequences paused avery@example.com after 3 bounces in a row. 4 enrollments are active on it and waiting. Re-check the addresses, then open Mailboxes and select Resume.'
1543
+ },
1544
+ {
1545
+ name: 'notice.details',
1546
+ description: 'The facts, as "Label: value" lines',
1547
+ sample: 'Mailbox: avery@example.com\nStatus: Paused by Sequences\nEnrollments waiting: 4'
1548
+ },
1549
+ {
1550
+ name: 'notice.url',
1551
+ description: 'Where the reader acts on it',
1552
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/outreach/mailboxes`
1553
+ },
1554
+ {
1555
+ name: 'notice.action',
1556
+ description: 'The button’s words',
1557
+ sample: 'Open Mailboxes to resume'
1558
+ },
1559
+ {
1560
+ name: 'notice.reason',
1561
+ description: 'Why this reader is getting it',
1562
+ sample: 'You are getting this because the mailbox is yours, or you manage the organization it belongs to.'
1218
1563
  }
1219
1564
  ],
1220
1565
  // The subject heads the body (AGL-3432): a reader who skips the
1221
1566
  // subject line still sees what the notice is about.
1222
1567
  defaultBody: [
1568
+ {
1569
+ block: 'text',
1570
+ text: '{{org.name}}',
1571
+ variant: 'eyebrow'
1572
+ },
1223
1573
  {
1224
1574
  block: 'text',
1225
1575
  text: '{{notice.subject}}',
@@ -1227,8 +1577,23 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1227
1577
  },
1228
1578
  {
1229
1579
  block: 'text',
1230
- text: '{{notice.body}}',
1580
+ text: '{{notice.lead}}',
1231
1581
  variant: 'body'
1582
+ },
1583
+ {
1584
+ block: 'text',
1585
+ text: '{{notice.details}}',
1586
+ variant: 'details'
1587
+ },
1588
+ {
1589
+ block: 'button',
1590
+ label: '{{notice.action}}',
1591
+ href: '{{notice.url}}'
1592
+ },
1593
+ {
1594
+ block: 'text',
1595
+ text: '{{notice.reason}}',
1596
+ variant: 'caption'
1232
1597
  }
1233
1598
  ],
1234
1599
  footerReason: 'You’re receiving this because you’re a member of {{org.name}} on ' + '{{brand.productName}}.',
@@ -1263,6 +1628,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1263
1628
  }
1264
1629
  ],
1265
1630
  defaultBody: [
1631
+ {
1632
+ block: 'text',
1633
+ text: '{{org.name}}',
1634
+ variant: 'eyebrow'
1635
+ },
1266
1636
  {
1267
1637
  block: 'text',
1268
1638
  text: 'Confirm this address',
@@ -1270,9 +1640,14 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1270
1640
  },
1271
1641
  {
1272
1642
  block: 'text',
1273
- text: '{{member.name}} asked to add {{address}} as one of their own ' + 'email addresses in the {{org.name}} workspace on ' + '{{brand.productName}}. To confirm it, open the link while ' + 'signed in as that member.',
1643
+ text: '{{member.name}} asked to add {{address}} as one of their own email addresses in {{org.name}}. Open the link while signed in as that member to confirm it.',
1274
1644
  variant: 'body'
1275
1645
  },
1646
+ {
1647
+ block: 'text',
1648
+ text: 'Address: {{address}}\nWorkspace: {{org.name}}\nFor: {{member.name}}',
1649
+ variant: 'details'
1650
+ },
1276
1651
  {
1277
1652
  block: 'button',
1278
1653
  label: 'Confirm the address',
@@ -1280,12 +1655,7 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1280
1655
  },
1281
1656
  {
1282
1657
  block: 'text',
1283
- text: 'Once it is confirmed, email sent from {{address}} with the ' + 'workspace’s capture address in BCC is filed under the person it ' + 'was written to. The link works for 24 hours.',
1284
- variant: 'body'
1285
- },
1286
- {
1287
- block: 'text',
1288
- text: 'If you did not expect this email, ignore it. Nothing changes ' + 'unless the member who asked opens the link.',
1658
+ text: 'Once confirmed, email sent from {{address}} with the workspace’s capture address in BCC is filed under the person it was written to. The link works for 24 hours. If you did not expect this, ignore it.',
1289
1659
  variant: 'caption'
1290
1660
  }
1291
1661
  ],
@@ -1313,17 +1683,132 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1313
1683
  name: 'settingsUrl',
1314
1684
  description: 'Notification settings, where the digest is turned off',
1315
1685
  sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`
1686
+ },
1687
+ {
1688
+ name: 'digest.eyebrow',
1689
+ description: 'The workspace and the day',
1690
+ sample: 'Test Org · Friday, September 28'
1691
+ },
1692
+ {
1693
+ name: 'digest.summary',
1694
+ description: 'What is owed today, in one line',
1695
+ sample: '1 task due today, 2 overdue, 3 unworked leads.'
1696
+ },
1697
+ {
1698
+ name: 'digest.overdueHeading',
1699
+ description: 'The overdue list’s heading, empty when there is none',
1700
+ sample: 'Overdue (2)'
1701
+ },
1702
+ {
1703
+ name: 'digest.overdue',
1704
+ description: 'Overdue tasks, one "Title — when" per line',
1705
+ sample: 'Call back Jordan — Main site · Thu, Sep 27, 9:00 AM CDT\nSend the proposal — Fri, Sep 28, 8:00 AM CDT'
1706
+ },
1707
+ {
1708
+ name: 'digest.todayHeading',
1709
+ description: 'The due-today list’s heading',
1710
+ sample: 'Due today (1)'
1711
+ },
1712
+ {
1713
+ name: 'digest.today',
1714
+ description: 'Tasks due today, one per line',
1715
+ sample: 'Follow up with Priya — Main site · Fri, Sep 28, 3:00 PM CDT'
1716
+ },
1717
+ {
1718
+ name: 'digest.leadsHeading',
1719
+ description: 'The unworked leads list’s heading',
1720
+ sample: 'Unworked leads (3)'
1721
+ },
1722
+ {
1723
+ name: 'digest.leads',
1724
+ description: 'Unworked leads, one "Name — site · first seen" per line',
1725
+ sample: 'Jane Doe — Main site · first seen Sep 26\nsam@example.com — Main site · first seen Sep 27'
1726
+ },
1727
+ {
1728
+ name: 'digest.nurturing',
1729
+ description: 'The leads in sequences or campaigns, or empty',
1730
+ sample: '2 leads are in sequences or campaigns.'
1731
+ },
1732
+ {
1733
+ name: 'digest.url',
1734
+ description: 'Where the reader starts: the Tasks section, else the leads',
1735
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks`
1736
+ },
1737
+ {
1738
+ name: 'digest.action',
1739
+ description: 'The button’s words',
1740
+ sample: 'Open your tasks'
1741
+ },
1742
+ {
1743
+ name: 'digest.links',
1744
+ description: 'Each site’s leads, one "Leads on Site — URL" per line',
1745
+ sample: `Leads on Main site — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/leads`
1316
1746
  }
1317
1747
  ],
1318
1748
  defaultBody: [
1319
1749
  {
1320
1750
  block: 'text',
1321
- text: '{{digest.body}}',
1751
+ text: '{{digest.eyebrow}}',
1752
+ variant: 'eyebrow'
1753
+ },
1754
+ {
1755
+ block: 'text',
1756
+ text: 'Your day in the CRM',
1757
+ variant: 'heading'
1758
+ },
1759
+ {
1760
+ block: 'text',
1761
+ text: '{{digest.summary}}',
1322
1762
  variant: 'body'
1323
1763
  },
1324
1764
  {
1325
1765
  block: 'text',
1326
- text: 'Change what you are emailed about: {{settingsUrl}}',
1766
+ text: '{{digest.overdueHeading}}',
1767
+ variant: 'subheading'
1768
+ },
1769
+ {
1770
+ block: 'text',
1771
+ text: '{{digest.overdue}}',
1772
+ variant: 'details'
1773
+ },
1774
+ {
1775
+ block: 'text',
1776
+ text: '{{digest.todayHeading}}',
1777
+ variant: 'subheading'
1778
+ },
1779
+ {
1780
+ block: 'text',
1781
+ text: '{{digest.today}}',
1782
+ variant: 'details'
1783
+ },
1784
+ {
1785
+ block: 'text',
1786
+ text: '{{digest.leadsHeading}}',
1787
+ variant: 'subheading'
1788
+ },
1789
+ {
1790
+ block: 'text',
1791
+ text: '{{digest.leads}}',
1792
+ variant: 'details'
1793
+ },
1794
+ {
1795
+ block: 'text',
1796
+ text: '{{digest.nurturing}}',
1797
+ variant: 'caption'
1798
+ },
1799
+ {
1800
+ block: 'button',
1801
+ label: '{{digest.action}}',
1802
+ href: '{{digest.url}}'
1803
+ },
1804
+ {
1805
+ block: 'text',
1806
+ text: '{{digest.links}}',
1807
+ variant: 'links'
1808
+ },
1809
+ {
1810
+ block: 'text',
1811
+ text: 'Turn the digest off, or change what you are emailed about: {{settingsUrl}}',
1327
1812
  variant: 'caption'
1328
1813
  }
1329
1814
  ],
@@ -1351,14 +1836,69 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1351
1836
  name: 'settingsUrl',
1352
1837
  description: 'Notification settings, where reminders are turned off',
1353
1838
  sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`
1839
+ },
1840
+ {
1841
+ name: 'reminder.eyebrow',
1842
+ description: 'The workspace the task is in',
1843
+ sample: 'Test Org'
1844
+ },
1845
+ {
1846
+ name: 'reminder.intro',
1847
+ description: 'What this is, in one sentence',
1848
+ sample: 'A reminder about your task. Open it to see the contact or deal it is for.'
1849
+ },
1850
+ {
1851
+ name: 'reminder.details',
1852
+ description: 'Each task as "Title — due …"',
1853
+ sample: 'Call back Jordan — due today at 9:00 AM CDT'
1854
+ },
1855
+ {
1856
+ name: 'reminder.url',
1857
+ description: 'The task, or the first one when there are several',
1858
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-1`
1859
+ },
1860
+ {
1861
+ name: 'reminder.action',
1862
+ description: 'The button’s words',
1863
+ sample: 'Open the task'
1864
+ },
1865
+ {
1866
+ name: 'reminder.links',
1867
+ description: 'For several tasks, each one’s link as "Title — URL"; empty for one',
1868
+ sample: `Call back Jordan — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-1\nSend the proposal — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-2`
1354
1869
  }
1355
1870
  ],
1356
1871
  defaultBody: [
1357
1872
  {
1358
1873
  block: 'text',
1359
- text: '{{reminder.body}}',
1874
+ text: '{{reminder.eyebrow}}',
1875
+ variant: 'eyebrow'
1876
+ },
1877
+ {
1878
+ block: 'text',
1879
+ text: '{{reminder.subject}}',
1880
+ variant: 'heading'
1881
+ },
1882
+ {
1883
+ block: 'text',
1884
+ text: '{{reminder.intro}}',
1360
1885
  variant: 'body'
1361
1886
  },
1887
+ {
1888
+ block: 'text',
1889
+ text: '{{reminder.details}}',
1890
+ variant: 'details'
1891
+ },
1892
+ {
1893
+ block: 'button',
1894
+ label: '{{reminder.action}}',
1895
+ href: '{{reminder.url}}'
1896
+ },
1897
+ {
1898
+ block: 'text',
1899
+ text: '{{reminder.links}}',
1900
+ variant: 'links'
1901
+ },
1362
1902
  {
1363
1903
  block: 'text',
1364
1904
  text: 'Change what you are emailed about: {{settingsUrl}}',
@@ -1384,9 +1924,39 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1384
1924
  name: 'digest.body',
1385
1925
  description: 'The insights, numbered, with their links',
1386
1926
  sample: '1. Visits from search rose 18% on last week.'
1927
+ },
1928
+ {
1929
+ name: 'digest.eyebrow',
1930
+ description: 'The workspace and the week',
1931
+ sample: 'Test Org · Oct 5 – Oct 11'
1932
+ },
1933
+ {
1934
+ name: 'digest.intro',
1935
+ description: 'What the insights are, in one sentence',
1936
+ sample: 'What Test Site\'s figures showed last week. Each one is traced to the figures it cites, so you can check it on the Analytics page.'
1937
+ },
1938
+ {
1939
+ name: 'digest.insights',
1940
+ description: 'The insights, numbered',
1941
+ sample: '1. Visits from search rose 18% on last week.\n\n2. The pricing page was the most viewed page, with 312 views.'
1942
+ },
1943
+ {
1944
+ name: 'digest.analyticsUrl',
1945
+ description: 'The site’s Analytics page',
1946
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/hosts/test-site/analytics`
1947
+ },
1948
+ {
1949
+ name: 'digest.why',
1950
+ description: 'Why it came, what it cost and how to turn it off',
1951
+ sample: `You asked for weekly insights for Test Org. Writing these used 21 of Test Org’s AI credits. Turn them off in Notifications: ${SAMPLE_CONSOLE_ORIGIN}/manage/notifications`
1387
1952
  }
1388
1953
  ],
1389
1954
  defaultBody: [
1955
+ {
1956
+ block: 'text',
1957
+ text: '{{digest.eyebrow}}',
1958
+ variant: 'eyebrow'
1959
+ },
1390
1960
  {
1391
1961
  block: 'text',
1392
1962
  text: 'Weekly insights for {{site.name}}',
@@ -1394,8 +1964,23 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1394
1964
  },
1395
1965
  {
1396
1966
  block: 'text',
1397
- text: '{{digest.body}}',
1967
+ text: '{{digest.intro}}',
1968
+ variant: 'body'
1969
+ },
1970
+ {
1971
+ block: 'text',
1972
+ text: '{{digest.insights}}',
1398
1973
  variant: 'body'
1974
+ },
1975
+ {
1976
+ block: 'button',
1977
+ label: 'Open {{site.name}} analytics',
1978
+ href: '{{digest.analyticsUrl}}'
1979
+ },
1980
+ {
1981
+ block: 'text',
1982
+ text: '{{digest.why}}',
1983
+ variant: 'caption'
1399
1984
  }
1400
1985
  ],
1401
1986
  footerReason: 'You’re receiving this because you turned on weekly insights in ' + '{{brand.productName}}.',
@@ -1571,13 +2156,73 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1571
2156
  name: 'receipt.body',
1572
2157
  description: 'The receipt as the intake wrote it',
1573
2158
  sample: 'We have received your report about https://example.com.\n\nYour reference is AR-3F9K2.'
2159
+ },
2160
+ {
2161
+ name: 'receipt.eyebrow',
2162
+ description: 'The reference',
2163
+ sample: 'Receipt · AR-3F9K2'
2164
+ },
2165
+ {
2166
+ name: 'receipt.heading',
2167
+ description: 'What was received',
2168
+ sample: 'We received your report'
2169
+ },
2170
+ {
2171
+ name: 'receipt.intro',
2172
+ description: 'What it was about',
2173
+ sample: 'We have received your report about https://example.com.'
2174
+ },
2175
+ {
2176
+ name: 'receipt.details',
2177
+ description: 'Reference, address and time, as "Label: value" lines',
2178
+ sample: 'Reference: AR-3F9K2\nAbout: https://example.com\nReceived: 2026-09-28 14:03 UTC'
2179
+ },
2180
+ {
2181
+ name: 'receipt.next',
2182
+ description: 'What happens next',
2183
+ sample: 'We do not publish what we decide about individual sites, and we will not share your details with the site\'s owner unless the law requires it.'
2184
+ },
2185
+ {
2186
+ name: 'receipt.keep',
2187
+ description: 'Keep this email, and the sign-off',
2188
+ sample: 'Keep this email. It is your record that we received the message above, and the reference is how we will find it if you write to us about it.'
1574
2189
  }
1575
2190
  ],
1576
2191
  defaultBody: [
1577
2192
  {
1578
2193
  block: 'text',
1579
- text: '{{receipt.body}}',
2194
+ text: '{{receipt.eyebrow}}',
2195
+ variant: 'eyebrow'
2196
+ },
2197
+ {
2198
+ block: 'text',
2199
+ text: '{{receipt.heading}}',
2200
+ variant: 'heading'
2201
+ },
2202
+ {
2203
+ block: 'text',
2204
+ text: '{{receipt.intro}}',
1580
2205
  variant: 'body'
2206
+ },
2207
+ {
2208
+ block: 'text',
2209
+ text: '{{receipt.details}}',
2210
+ variant: 'details'
2211
+ },
2212
+ {
2213
+ block: 'text',
2214
+ text: 'What happens next',
2215
+ variant: 'subheading'
2216
+ },
2217
+ {
2218
+ block: 'text',
2219
+ text: '{{receipt.next}}',
2220
+ variant: 'body'
2221
+ },
2222
+ {
2223
+ block: 'text',
2224
+ text: '{{receipt.keep}}',
2225
+ variant: 'caption'
1581
2226
  }
1582
2227
  ],
1583
2228
  footerReason: 'You’re receiving this because this address was given on a report ' + 'or notice sent to {{brand.productName}}.',
@@ -1599,13 +2244,48 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
1599
2244
  name: 'review.body',
1600
2245
  description: 'The decision as review wrote it',
1601
2246
  sample: 'Test Plugin 1.2.0 passed review and is live in the marketplace.'
2247
+ },
2248
+ {
2249
+ name: 'review.details',
2250
+ description: 'Plugin, version and outcome as "Label: value" lines',
2251
+ sample: 'Plugin: Test Plugin\nVersion: 1.2.0\nOutcome: Approved'
2252
+ },
2253
+ {
2254
+ name: 'review.url',
2255
+ description: 'The publisher’s Marketplace page',
2256
+ sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/marketplace`
1602
2257
  }
1603
2258
  ],
1604
2259
  defaultBody: [
2260
+ {
2261
+ block: 'text',
2262
+ text: 'Marketplace review',
2263
+ variant: 'eyebrow'
2264
+ },
2265
+ {
2266
+ block: 'text',
2267
+ text: '{{review.subject}}',
2268
+ variant: 'heading'
2269
+ },
1605
2270
  {
1606
2271
  block: 'text',
1607
2272
  text: '{{review.body}}',
1608
2273
  variant: 'body'
2274
+ },
2275
+ {
2276
+ block: 'text',
2277
+ text: '{{review.details}}',
2278
+ variant: 'details'
2279
+ },
2280
+ {
2281
+ block: 'button',
2282
+ label: 'Open your marketplace listings',
2283
+ href: '{{review.url}}'
2284
+ },
2285
+ {
2286
+ block: 'text',
2287
+ text: 'Questions about a review? Contact support: {{brand.supportUrl}}',
2288
+ variant: 'caption'
1609
2289
  }
1610
2290
  ],
1611
2291
  footerReason: 'You’re receiving this because you manage a plugin published on ' + '{{brand.productName}}.',