@dbx-tools/email 0.3.20 → 0.3.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +34 -0
  2. package/package.json +3 -3
  3. package/src/config.ts +12 -12
package/README.md CHANGED
@@ -144,6 +144,40 @@ const html = emailHtml.renderEmailHtml({
144
144
  `markdown.markdownToHtml()` renders Markdown. `emailHtml.renderEmailHtml()` wraps
145
145
  the rendered body in the package layout and inlines CSS for mail clients.
146
146
 
147
+ ## Brand The Email
148
+
149
+ Branding is optional. Pass a `brand` to the plugin (or to `renderEmailHtml`) to
150
+ color the layout with an accent, font, and header logo; omit it for the neutral
151
+ default palette.
152
+
153
+ ```ts
154
+ import { brand, plugin } from "@dbx-tools/email";
155
+
156
+ // The dbx-tools brand, ready to use:
157
+ plugin.email({ brand: brand.defaultEmailBrand });
158
+
159
+ // Or derive from any shared BrandContext:
160
+ import { brand as coreBrand } from "@dbx-tools/shared-core";
161
+ plugin.email({ brand: brand.emailBrandFromContext(coreBrand.defaultBrandContext) });
162
+
163
+ // Or hand-build the small email-safe slice:
164
+ plugin.email({
165
+ brand: {
166
+ accent: "#FF3621",
167
+ fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif",
168
+ name: "Acme",
169
+ logoUrl: "https://acme.example/logo.svg", // http(s): or data: only
170
+ },
171
+ });
172
+ ```
173
+
174
+ The brand is inlined into every rendered message. The browser UI's `[data-brand]`
175
+ CSS bridge can't reach an inbox (mail clients strip `<style>` and ignore `var()`),
176
+ so email branding uses inline token values instead. A `logoUrl` renders only when
177
+ it is an `http(s):` or `data:` URL - a package-export asset path is dropped rather
178
+ than shown as a broken image, so `defaultEmailBrand` applies the brand color and
179
+ font but no logo.
180
+
147
181
  ## Use The Outbox In Tests
148
182
 
149
183
  ```ts
package/package.json CHANGED
@@ -19,15 +19,15 @@
19
19
  "juice": "^12.1.1",
20
20
  "marked": "^18.0.5",
21
21
  "nodemailer": "^7.0.13",
22
- "@dbx-tools/shared-core": "0.3.20",
23
- "@dbx-tools/shared-email": "0.3.20"
22
+ "@dbx-tools/shared-core": "0.3.22",
23
+ "@dbx-tools/shared-email": "0.3.22"
24
24
  },
25
25
  "main": "index.ts",
26
26
  "license": "UNLICENSED",
27
27
  "publishConfig": {
28
28
  "access": "public"
29
29
  },
30
- "version": "0.3.20",
30
+ "version": "0.3.22",
31
31
  "types": "index.ts",
32
32
  "type": "module",
33
33
  "exports": {
package/src/config.ts CHANGED
@@ -22,10 +22,10 @@
22
22
  *
23
23
  * @module
24
24
  */
25
+ import { resolve } from "node:path";
25
26
  import type { BasePluginConfig } from "@databricks/appkit";
26
- import type { JSONSchema7 } from "json-schema";
27
27
  import { object } from "@dbx-tools/shared-core";
28
- import { resolve } from "node:path";
28
+ import type { JSONSchema7 } from "json-schema";
29
29
  import type { EmailBrand } from "./brand";
30
30
  import { parseAllowedSenders } from "./sender";
31
31
 
@@ -162,12 +162,12 @@ export const EMAIL_CONFIG_SCHEMA: JSONSchema7 = {
162
162
  /** Parse the `SMTP_SECURE` env / config flag, defaulting to `port === 465`. */
163
163
  function resolveSecure(flag: boolean | undefined, port: number): boolean {
164
164
  if (typeof flag === "boolean") return flag;
165
- return object.toBoolean(process.env["SMTP_SECURE"]) ?? port === 465;
165
+ return object.toBoolean(process.env.SMTP_SECURE) ?? port === 465;
166
166
  }
167
167
 
168
168
  /** Whether `EMAIL_OUTBOX_MODE` explicitly opts into the file/outbox fallback. */
169
169
  function isOutboxModeEnabled(): boolean {
170
- return object.toBoolean(process.env["EMAIL_OUTBOX_MODE"]) ?? false;
170
+ return object.toBoolean(process.env.EMAIL_OUTBOX_MODE) ?? false;
171
171
  }
172
172
 
173
173
  const SMTP_REQUIRED_FIELDS = ["SMTP_HOST", "SMTP_USER", "SMTP_PASSWORD"] as const;
@@ -197,13 +197,13 @@ function missingSmtpFields(
197
197
  */
198
198
  export function resolveEmailConfig(config: EmailPluginConfig = {}): ResolvedEmailConfig {
199
199
  const smtp = config.smtp ?? {};
200
- const host = smtp.host ?? process.env["SMTP_HOST"];
201
- const user = smtp.user ?? process.env["SMTP_USER"];
202
- const pass = smtp.password ?? process.env["SMTP_PASSWORD"];
203
- const domain = config.domain ?? process.env["EMAIL_DOMAIN"];
204
- const from = config.from ?? process.env["EMAIL_FROM"];
200
+ const host = smtp.host ?? process.env.SMTP_HOST;
201
+ const user = smtp.user ?? process.env.SMTP_USER;
202
+ const pass = smtp.password ?? process.env.SMTP_PASSWORD;
203
+ const domain = config.domain ?? process.env.EMAIL_DOMAIN;
204
+ const from = config.from ?? process.env.EMAIL_FROM;
205
205
  const allowedSenders = parseAllowedSenders(
206
- config.allowedSenders ?? process.env["EMAIL_ALLOWED_SENDERS"],
206
+ config.allowedSenders ?? process.env.EMAIL_ALLOWED_SENDERS,
207
207
  );
208
208
  const sender: ResolvedSender = {
209
209
  ...(domain ? { domain } : {}),
@@ -227,7 +227,7 @@ export function resolveEmailConfig(config: EmailPluginConfig = {}): ResolvedEmai
227
227
  "email: SMTP is configured but no sender source - set EMAIL_DOMAIN (to derive <user>@<domain>) or EMAIL_FROM (a fixed address)",
228
228
  );
229
229
  }
230
- const portRaw = smtp.port ?? Number(process.env["SMTP_PORT"]);
230
+ const portRaw = smtp.port ?? Number(process.env.SMTP_PORT);
231
231
  const port = Number.isFinite(portRaw) && portRaw ? Number(portRaw) : 587;
232
232
  return {
233
233
  mode: "smtp",
@@ -246,7 +246,7 @@ export function resolveEmailConfig(config: EmailPluginConfig = {}): ResolvedEmai
246
246
  }
247
247
 
248
248
  const outDir = resolve(
249
- config.outDir ?? process.env["EMAIL_OUTBOX_DIR"] ?? resolve(process.cwd(), "tmp"),
249
+ config.outDir ?? process.env.EMAIL_OUTBOX_DIR ?? resolve(process.cwd(), "tmp"),
250
250
  );
251
251
  return { mode: "file", outDir, ...sender };
252
252
  }