@nebutra/email 0.1.1 → 2.0.0

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.
package/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # @nebutra/email
2
2
 
3
- > Transactional email service powered by Resend with branded HTML templates.
3
+ Multi-provider transactional email for Nebutra products.
4
+
5
+ The package auto-detects Resend, Nodemailer SMTP, or a console development
6
+ provider, then sends branded HTML templates through a single API.
4
7
 
5
8
  ## Installation
6
9
 
7
10
  ```bash
8
- # Internal monorepo dependency
9
- pnpm add @nebutra/email@workspace:*
11
+ pnpm add @nebutra/email
10
12
  ```
11
13
 
12
14
  ## Usage
@@ -53,5 +55,20 @@ await sendApiKeyCreatedEmail({
53
55
 
54
56
  | Environment Variable | Description |
55
57
  |---------------------|-------------|
58
+ | `EMAIL_PROVIDER` | Optional explicit provider: `resend`, `nodemailer`, or `console` |
56
59
  | `RESEND_API_KEY` | Resend API key from https://resend.com/api-keys |
57
- | `EMAIL_FROM` | Verified sender address (default: `Nebutra <noreply@nebutra.ai>`) |
60
+ | `SMTP_HOST` | Enables Nodemailer SMTP provider when Resend is not configured |
61
+ | `SMTP_PORT` / `SMTP_USER` / `SMTP_PASS` / `SMTP_SECURE` | SMTP provider settings |
62
+ | `EMAIL_FROM` | Verified sender address (default: `Nebutra <noreply@nebutra.com>`) |
63
+
64
+ ## Providers
65
+
66
+ | Provider | Selection |
67
+ | --- | --- |
68
+ | `resend` | `EMAIL_PROVIDER=resend` or `RESEND_API_KEY` present |
69
+ | `nodemailer` | `EMAIL_PROVIDER=nodemailer` or `SMTP_HOST` present |
70
+ | `console` | Explicit `EMAIL_PROVIDER=console` or development/test fallback |
71
+
72
+ ## License
73
+
74
+ MIT
package/dist/index.d.ts CHANGED
@@ -251,7 +251,7 @@ declare const REACT_EMAIL_TEMPLATES: {
251
251
  *
252
252
  * Environment variables:
253
253
  * EMAIL_PROVIDER — explicit provider override (optional)
254
- * EMAIL_FROM — verified sender (e.g. "Nebutra <noreply@nebutra.ai>")
254
+ * EMAIL_FROM — verified sender (e.g. getBrandMailFrom() example)
255
255
  * RESEND_API_KEY — for Resend provider
256
256
  * SMTP_HOST — for Nodemailer provider (+ SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_SECURE)
257
257
  */
@@ -281,6 +281,12 @@ declare const EMAIL_TEMPLATE_CATALOG: readonly [{
281
281
  readonly description: "Passwordless sign-in link";
282
282
  readonly sendHelper: "sendMagicLinkEmail";
283
283
  readonly fileName: "magic-link-email.html";
284
+ }, {
285
+ readonly id: "email-change";
286
+ readonly label: "Email Change";
287
+ readonly description: "Confirm a new account email address";
288
+ readonly sendHelper: "sendEmailChangeEmail";
289
+ readonly fileName: "email-change-email.html";
284
290
  }, {
285
291
  readonly id: "contact-form-received";
286
292
  readonly label: "Contact Form Received";
@@ -333,7 +339,12 @@ declare function sendWelcomeEmail(opts: {
333
339
  declare function sendOrderConfirmationEmail(opts: {
334
340
  to: string;
335
341
  orderId: string;
342
+ /** Order total in minor units (integer cents). */
336
343
  totalAmount: number;
344
+ /** ISO 4217 currency code (default "USD"). */
345
+ currency?: string;
346
+ /** BCP 47 locale tag (default "en-US"). */
347
+ locale?: string;
337
348
  items: Array<{
338
349
  productId: string;
339
350
  quantity: number | string;
@@ -346,6 +357,16 @@ declare function sendMagicLinkEmail(opts: {
346
357
  to: string;
347
358
  magicLinkUrl: string;
348
359
  }): Promise<SendResult>;
360
+ /**
361
+ * Email-change verification sent to the *new* address (TODO #126).
362
+ * Confirming the link flips the account email.
363
+ */
364
+ declare function sendEmailChangeEmail(opts: {
365
+ to: string;
366
+ confirmUrl: string;
367
+ /** Optional display name for the new address (defaults to `to`). */
368
+ newEmail?: string;
369
+ }): Promise<SendResult>;
349
370
  /**
350
371
  * Contact Form Receipt (Sent to the User)
351
372
  */
@@ -391,4 +412,4 @@ declare function sendReceiptEmail(opts: {
391
412
  to: string;
392
413
  } & ReceiptEmailProps): Promise<SendResult>;
393
414
 
394
- export { ConsoleEmailProvider, EMAIL_TEMPLATE_CATALOG, type EmailProvider, type EmailProviderType, type EmailTemplateCatalogEntry, type InvitationEmailProps, NodemailerEmailProvider, type PasswordResetEmailProps, REACT_EMAIL_TEMPLATES, type ReactEmailTemplate, type ReceiptEmailProps, type RenderedEmail, ResendEmailProvider, type SendOptions, type SendResult, type WelcomeEmailProps, getEmailProvider, invitationEmail, passwordResetEmail, receiptEmail, render$2 as renderInvitationEmail, render$1 as renderPasswordResetEmail, render$3 as renderReceiptEmail, render as renderWelcomeEmail, resetEmailProvider, sendContactFormReceivedEmail, sendInvitationEmail, sendLicenseCreatedEmail, sendMagicLinkEmail, sendOrderConfirmationEmail, sendPasswordResetEmail, sendReceiptEmail, sendWelcomeEmail, sendWelcomeReactEmail, welcomeEmail };
415
+ export { ConsoleEmailProvider, EMAIL_TEMPLATE_CATALOG, type EmailProvider, type EmailProviderType, type EmailTemplateCatalogEntry, type InvitationEmailProps, NodemailerEmailProvider, type PasswordResetEmailProps, REACT_EMAIL_TEMPLATES, type ReactEmailTemplate, type ReceiptEmailProps, type RenderedEmail, ResendEmailProvider, type SendOptions, type SendResult, type WelcomeEmailProps, getEmailProvider, invitationEmail, passwordResetEmail, receiptEmail, render$2 as renderInvitationEmail, render$1 as renderPasswordResetEmail, render$3 as renderReceiptEmail, render as renderWelcomeEmail, resetEmailProvider, sendContactFormReceivedEmail, sendEmailChangeEmail, sendInvitationEmail, sendLicenseCreatedEmail, sendMagicLinkEmail, sendOrderConfirmationEmail, sendPasswordResetEmail, sendReceiptEmail, sendWelcomeEmail, sendWelcomeReactEmail, welcomeEmail };
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ // src/index.ts
2
+ import { brand, colors as colors3 } from "@nebutra/brand/metadata";
3
+ import { getBrandMailFrom, getBrandOrigin as getBrandOrigin2 } from "@nebutra/brand/metadata-helpers";
4
+
1
5
  // src/providers/console.ts
2
6
  var counter = 0;
3
7
  var ConsoleEmailProvider = class {
@@ -134,8 +138,13 @@ function resetEmailProvider() {
134
138
  cachedProvider = void 0;
135
139
  }
136
140
 
141
+ // src/templates/invitation.tsx
142
+ import { colors as colors2 } from "@nebutra/brand/metadata";
143
+
137
144
  // src/templates/_layout.ts
138
- var BRAND_GRADIENT = "linear-gradient(135deg,#0033FE,#0BF1C3)";
145
+ import { colors } from "@nebutra/brand/metadata";
146
+ import { getBrandOrigin } from "@nebutra/brand/metadata-helpers";
147
+ var BRAND_HEADER = colors.primary["500"];
139
148
  var COLOR_BG = "#f8fafc";
140
149
  var COLOR_BORDER = "#e2e8f0";
141
150
  var COLOR_HEADING = "#0f172a";
@@ -155,7 +164,7 @@ function baseLayout({ brandName, preview: preview5, body }) {
155
164
  <table width="100%" cellpadding="0" cellspacing="0" role="presentation" style="background:${COLOR_BG};">
156
165
  <tr><td align="center" style="padding:40px 16px;">
157
166
  <table width="600" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;border-radius:12px;border:1px solid ${COLOR_BORDER};overflow:hidden;max-width:600px;width:100%;">
158
- <tr><td style="background:${BRAND_GRADIENT};padding:32px 40px;">
167
+ <tr><td style="background:${BRAND_HEADER};padding:32px 40px;">
159
168
  <h1 style="margin:0;color:#ffffff;font-size:24px;font-weight:700;letter-spacing:-0.5px;">${escapeHtml(brandName)}</h1>
160
169
  </td></tr>
161
170
  <tr><td style="padding:40px;">
@@ -164,8 +173,8 @@ function baseLayout({ brandName, preview: preview5, body }) {
164
173
  <tr><td style="padding:24px 40px;border-top:1px solid ${COLOR_BORDER};background:${COLOR_BG};">
165
174
  <p style="margin:0;font-size:12px;color:${COLOR_MUTED};text-align:center;">
166
175
  &copy; ${(/* @__PURE__ */ new Date()).getFullYear()} ${escapeHtml(brandName)} &middot;
167
- <a href="https://nebutra.ai/privacy" style="color:${COLOR_MUTED};">Privacy</a> &middot;
168
- <a href="https://nebutra.ai/unsubscribe" style="color:${COLOR_MUTED};">Unsubscribe</a>
176
+ <a href="${getBrandOrigin("landing")}/privacy" style="color:${COLOR_MUTED};">Privacy</a> &middot;
177
+ <a href="${getBrandOrigin("landing")}/unsubscribe" style="color:${COLOR_MUTED};">Unsubscribe</a>
169
178
  </p>
170
179
  </td></tr>
171
180
  </table>
@@ -175,7 +184,9 @@ function baseLayout({ brandName, preview: preview5, body }) {
175
184
  </html>`;
176
185
  }
177
186
  var palette = {
178
- gradient: BRAND_GRADIENT,
187
+ /** @deprecated alias of solid identity header — not a product skin */
188
+ gradient: BRAND_HEADER,
189
+ header: BRAND_HEADER,
179
190
  background: COLOR_BG,
180
191
  border: COLOR_BORDER,
181
192
  heading: COLOR_HEADING,
@@ -208,7 +219,7 @@ function render(props) {
208
219
  </p>
209
220
  <p style="margin:0 0 24px;font-size:14px;color:${palette.body};">
210
221
  Role:
211
- <span style="display:inline-block;background:#e0f2fe;color:#0033FE;padding:4px 10px;border-radius:999px;font-size:13px;font-weight:600;margin-left:6px;">
222
+ <span style="display:inline-block;background:#e0f2fe;color:${colors2.primary["500"]};padding:4px 10px;border-radius:999px;font-size:13px;font-weight:600;margin-left:6px;">
212
223
  ${role}
213
224
  </span>
214
225
  </p>
@@ -386,7 +397,7 @@ var REACT_EMAIL_TEMPLATES = {
386
397
  };
387
398
 
388
399
  // src/index.ts
389
- var FROM = process.env.EMAIL_FROM ?? "Nebutra <noreply@nebutra.ai>";
400
+ var FROM = process.env.EMAIL_FROM ?? getBrandMailFrom();
390
401
  var EMAIL_TEMPLATE_CATALOG = [
391
402
  {
392
403
  id: "welcome",
@@ -409,6 +420,13 @@ var EMAIL_TEMPLATE_CATALOG = [
409
420
  sendHelper: "sendMagicLinkEmail",
410
421
  fileName: "magic-link-email.html"
411
422
  },
423
+ {
424
+ id: "email-change",
425
+ label: "Email Change",
426
+ description: "Confirm a new account email address",
427
+ sendHelper: "sendEmailChangeEmail",
428
+ fileName: "email-change-email.html"
429
+ },
412
430
  {
413
431
  id: "contact-form-received",
414
432
  label: "Contact Form Received",
@@ -466,7 +484,7 @@ function baseLayout2(content, previewText = "") {
466
484
  <meta charset="UTF-8" />
467
485
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
468
486
  <meta name="x-apple-disable-message-reformatting" />
469
- <title>Nebutra</title>
487
+ <title>${brand.name}</title>
470
488
  <!--[if mso]><noscript><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml></noscript><![endif]-->
471
489
  </head>
472
490
  <body style="margin:0;padding:0;background:#f8fafc;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
@@ -475,8 +493,8 @@ function baseLayout2(content, previewText = "") {
475
493
  <tr><td align="center" style="padding:40px 16px;">
476
494
  <table width="600" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;border-radius:12px;border:1px solid #e2e8f0;overflow:hidden;max-width:600px;width:100%;">
477
495
  <!-- Header -->
478
- <tr><td style="background:linear-gradient(135deg,#0033FE,#0BF1C3);padding:32px 40px;">
479
- <h1 style="margin:0;color:#ffffff;font-size:24px;font-weight:700;letter-spacing:-0.5px;">Nebutra</h1>
496
+ <tr><td style="background:${colors3.primary["500"]};padding:32px 40px;">
497
+ <h1 style="margin:0;color:#ffffff;font-size:24px;font-weight:700;letter-spacing:-0.5px;">${brand.name}</h1>
480
498
  </td></tr>
481
499
  <!-- Body -->
482
500
  <tr><td style="padding:40px;">
@@ -485,9 +503,9 @@ function baseLayout2(content, previewText = "") {
485
503
  <!-- Footer -->
486
504
  <tr><td style="padding:24px 40px;border-top:1px solid #e2e8f0;background:#f8fafc;">
487
505
  <p style="margin:0;font-size:12px;color:#94a3b8;text-align:center;">
488
- \xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} Nebutra Intelligence Inc. \xB7
489
- <a href="https://nebutra.ai/privacy" style="color:#94a3b8;">Privacy</a> \xB7
490
- <a href="https://nebutra.ai/unsubscribe" style="color:#94a3b8;">Unsubscribe</a>
506
+ \xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brand.nameFullEn} \xB7
507
+ <a href="${getBrandOrigin2("landing")}/privacy" style="color:#94a3b8;">Privacy</a> \xB7
508
+ <a href="${getBrandOrigin2("landing")}/unsubscribe" style="color:#94a3b8;">Unsubscribe</a>
491
509
  </p>
492
510
  </td></tr>
493
511
  </table>
@@ -497,31 +515,35 @@ function baseLayout2(content, previewText = "") {
497
515
  </html>`;
498
516
  }
499
517
  async function sendWelcomeEmail(opts) {
500
- const dashboardUrl = opts.dashboardUrl ?? "https://app.nebutra.ai";
518
+ const dashboardUrl = opts.dashboardUrl ?? getBrandOrigin2("app");
501
519
  const html = baseLayout2(
502
520
  `
503
- <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Welcome to Nebutra, ${opts.firstName}!</h2>
521
+ <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Welcome to ${brand.name}, ${opts.firstName}!</h2>
504
522
  <p style="margin:0 0 16px;font-size:15px;color:#475569;line-height:1.6;">
505
523
  Your workspace <strong>${opts.orgName}</strong> is ready. You can now invite team members,
506
- create API keys, and start building with the Nebutra platform.
524
+ create API keys, and start building with the ${brand.name} platform.
507
525
  </p>
508
- <a href="${dashboardUrl}" style="display:inline-block;background:linear-gradient(135deg,#0033FE,#0BF1C3);color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:15px;font-weight:600;margin:0 0 24px;">
526
+ <a href="${dashboardUrl}" style="display:inline-block;background:${colors3.primary["500"]};color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:15px;font-weight:600;margin:0 0 24px;">
509
527
  Open Dashboard \u2192
510
528
  </a>
511
529
  <p style="margin:0;font-size:13px;color:#94a3b8;">
512
- If you have questions, reply to this email or visit our <a href="https://docs.nebutra.ai" style="color:#0033FE;">documentation</a>.
530
+ If you have questions, reply to this email or visit our <a href="${getBrandOrigin2("docs")}" style="color:${colors3.primary["500"]};">documentation</a>.
513
531
  </p>
514
532
  `,
515
- `Welcome to Nebutra \u2014 ${opts.orgName} is ready`
533
+ `Welcome to ${brand.name} \u2014 ${opts.orgName} is ready`
516
534
  );
517
535
  return send({
518
536
  to: opts.to,
519
- subject: `Welcome to Nebutra \u2014 ${opts.orgName} is ready`,
537
+ subject: `Welcome to ${brand.name} \u2014 ${opts.orgName} is ready`,
520
538
  html,
521
539
  tags: [{ name: "type", value: "welcome" }]
522
540
  });
523
541
  }
524
542
  async function sendOrderConfirmationEmail(opts) {
543
+ const formattedTotal = new Intl.NumberFormat(opts.locale ?? "en-US", {
544
+ style: "currency",
545
+ currency: opts.currency ?? "USD"
546
+ }).format(opts.totalAmount / 100);
525
547
  const itemsHtml = opts.items.map(
526
548
  (item) => `<tr>
527
549
  <td style="padding:12px 0;border-bottom:1px solid #e2e8f0;color:#0f172a;font-size:15px;">${item.productId}</td>
@@ -532,13 +554,13 @@ async function sendOrderConfirmationEmail(opts) {
532
554
  `
533
555
  <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Order Confirmed!</h2>
534
556
  <p style="margin:0 0 16px;font-size:15px;color:#475569;line-height:1.6;">
535
- Thank you for your order <strong>#${opts.orderId}</strong>. We've received your payment of
536
- <strong>$${(opts.totalAmount / 100).toFixed(2)}</strong> and your order is now being processed.
557
+ Thank you for your order <strong>#${opts.orderId}</strong>. We've received your payment of
558
+ <strong>${formattedTotal}</strong> and your order is now being processed.
537
559
  </p>
538
560
  <table width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 24px;border-collapse:collapse;">
539
561
  ${itemsHtml}
540
562
  </table>
541
- <a href="https://app.nebutra.ai/orders/${opts.orderId}" style="display:inline-block;background:linear-gradient(135deg,#0033FE,#0BF1C3);color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:15px;font-weight:600;margin:0 0 24px;">
563
+ <a href="${getBrandOrigin2("app")}/orders/${opts.orderId}" style="display:inline-block;background:${colors3.primary["500"]};color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:15px;font-weight:600;margin:0 0 24px;">
542
564
  View Order Details \u2192
543
565
  </a>
544
566
  `,
@@ -554,11 +576,11 @@ async function sendOrderConfirmationEmail(opts) {
554
576
  async function sendMagicLinkEmail(opts) {
555
577
  const html = baseLayout2(
556
578
  `
557
- <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Sign in to Nebutra</h2>
579
+ <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Sign in to ${brand.name}</h2>
558
580
  <p style="margin:0 0 16px;font-size:15px;color:#475569;line-height:1.6;">
559
581
  Click the button below to sign in securely. No password required.
560
582
  </p>
561
- <a href="${opts.magicLinkUrl}" style="display:inline-block;background:linear-gradient(135deg,#0033FE,#0BF1C3);color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:16px;font-weight:600;margin:0 0 24px;text-align:center;width:100%;max-width:280px;">
583
+ <a href="${opts.magicLinkUrl}" style="display:inline-block;background:${colors3.primary["500"]};color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:16px;font-weight:600;margin:0 0 24px;text-align:center;width:100%;max-width:280px;">
562
584
  \u2728 Sign In Automatically
563
585
  </a>
564
586
  <p style="margin:0;font-size:12px;color:#94a3b8;line-height:1.4;">
@@ -566,15 +588,40 @@ async function sendMagicLinkEmail(opts) {
566
588
  This link expires in 15 minutes.
567
589
  </p>
568
590
  `,
569
- "Click here to sign in to your Nebutra account"
591
+ `Click here to sign in to your ${brand.name} account`
570
592
  );
571
593
  return send({
572
594
  to: opts.to,
573
- subject: "Sign in to Nebutra \u2728",
595
+ subject: `Sign in to ${brand.name} \u2728`,
574
596
  html,
575
597
  tags: [{ name: "type", value: "magic_link" }]
576
598
  });
577
599
  }
600
+ async function sendEmailChangeEmail(opts) {
601
+ const recipientEmail = opts.newEmail ?? opts.to;
602
+ const html = baseLayout2(
603
+ `
604
+ <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Confirm your new email address</h2>
605
+ <p style="margin:0 0 16px;font-size:15px;color:#475569;line-height:1.6;">
606
+ We received a request to change the email on your ${brand.name} account to
607
+ <strong>${recipientEmail}</strong>. Click the button below to confirm. This link expires in 1 hour.
608
+ </p>
609
+ <a href="${opts.confirmUrl}" style="display:inline-block;background:${colors3.primary["500"]};color:#ffffff;text-decoration:none;border-radius:8px;padding:12px 24px;font-size:16px;font-weight:600;margin:0 0 24px;text-align:center;width:100%;max-width:280px;">
610
+ Confirm email change \u2192
611
+ </a>
612
+ <p style="margin:0;font-size:12px;color:#94a3b8;line-height:1.4;">
613
+ If you did not request this change you can safely ignore this email \u2014 your address will not be updated.
614
+ </p>
615
+ `,
616
+ "Confirm your new Nebutra email address"
617
+ );
618
+ return send({
619
+ to: opts.to,
620
+ subject: "Confirm your new Nebutra email address",
621
+ html,
622
+ tags: [{ name: "type", value: "email_change_verification" }]
623
+ });
624
+ }
578
625
  async function sendContactFormReceivedEmail(opts) {
579
626
  const html = baseLayout2(
580
627
  `
@@ -587,14 +634,14 @@ async function sendContactFormReceivedEmail(opts) {
587
634
  We've received your request and our team will get back to you within 1-2 business days.
588
635
  </p>
589
636
  <p style="margin:0;font-size:15px;color:#475569;line-height:1.6;">
590
- Best regards,<br/>The Nebutra Team
637
+ Best regards,<br/>The ${brand.name} Team
591
638
  </p>
592
639
  `,
593
640
  "We have received your message"
594
641
  );
595
642
  return send({
596
643
  to: opts.to,
597
- subject: "We've received your message - Nebutra",
644
+ subject: `We've received your message - ${brand.name}`,
598
645
  html,
599
646
  tags: [{ name: "type", value: "contact_receipt" }]
600
647
  });
@@ -602,7 +649,7 @@ async function sendContactFormReceivedEmail(opts) {
602
649
  async function sendLicenseCreatedEmail(opts) {
603
650
  const html = baseLayout2(
604
651
  `
605
- <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Welcome to Nebutra-Sailor! \u{1F680}</h2>
652
+ <h2 style="margin:0 0 16px;font-size:22px;color:#0f172a;">Welcome to ${brand.name}-Sailor! \u{1F680}</h2>
606
653
  <p style="margin:0 0 16px;font-size:15px;color:#475569;line-height:1.6;">
607
654
  Hi ${opts.firstName}, your <strong>${opts.tier}</strong> license has been successfully generated.
608
655
  </p>
@@ -610,23 +657,23 @@ async function sendLicenseCreatedEmail(opts) {
610
657
  Your official License Key is:
611
658
  </p>
612
659
  <div style="background:#0f172a;border-radius:8px;padding:16px 20px;margin:0 0 24px;overflow-x:auto;">
613
- <code style="color:#0BF1C3;font-family:'Courier New',monospace;font-size:13px;word-break:break-all;">${opts.licenseKey}</code>
660
+ <code style="color:${colors3.accent["500"]};font-family:'Courier New',monospace;font-size:13px;word-break:break-all;">${opts.licenseKey}</code>
614
661
  </div>
615
662
  <p style="margin:0 0 16px;font-size:15px;color:#475569;line-height:1.6;">
616
- To unlock the premium capabilities of the Nebutra CLI locally, run the following command in your terminal:
663
+ To unlock the premium capabilities of the ${brand.name} CLI locally, run the following command in your terminal:
617
664
  </p>
618
665
  <div style="background:#f1f5f9;border:1px solid #e2e8f0;border-radius:6px;padding:12px;margin:0 0 24px;">
619
666
  <code style="color:#334155;font-family:'Courier New',monospace;font-size:13px;">nebutra license activate ${opts.licenseKey}</code>
620
667
  </div>
621
668
  <p style="margin:0;font-size:13px;color:#94a3b8;">
622
- If you have questions, reply to this email or visit our <a href="https://docs.nebutra.ai" style="color:#0033FE;">documentation</a>.
669
+ If you have questions, reply to this email or visit our <a href="${getBrandOrigin2("docs")}" style="color:${colors3.primary["500"]};">documentation</a>.
623
670
  </p>
624
671
  `,
625
- "Your Nebutra License Key is Ready"
672
+ `Your ${brand.name} License Key is Ready`
626
673
  );
627
674
  return send({
628
675
  to: opts.to,
629
- subject: `Your Nebutra License Key is Ready (${opts.tier})`,
676
+ subject: `Your ${brand.name} License Key is Ready (${opts.tier})`,
630
677
  html,
631
678
  tags: [{ name: "type", value: "license_created" }]
632
679
  });
@@ -679,6 +726,7 @@ export {
679
726
  render4 as renderWelcomeEmail,
680
727
  resetEmailProvider,
681
728
  sendContactFormReceivedEmail,
729
+ sendEmailChangeEmail,
682
730
  sendInvitationEmail,
683
731
  sendLicenseCreatedEmail,
684
732
  sendMagicLinkEmail,