@dbx-tools/email 0.9.153 → 0.9.157
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/index.ts +8 -8
- package/lib/index.d.ts +8 -8
- package/lib/index.js +9 -9
- package/lib/src/config.d.ts +1 -1
- package/lib/src/config.js +19 -21
- package/lib/src/email-html.d.ts +0 -3
- package/lib/src/email-html.js +1 -4
- package/lib/src/markdown.d.ts +0 -2
- package/lib/src/markdown.js +2 -4
- package/lib/src/outbox.d.ts +2 -2
- package/lib/src/outbox.js +3 -3
- package/lib/src/plugin.js +10 -10
- package/lib/src/sender.js +7 -7
- package/lib/src/tool.d.ts +2 -2
- package/lib/src/tool.js +7 -7
- package/lib/src/transport.js +5 -5
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -96
- package/src/config.ts +18 -27
- package/src/email-html.ts +0 -4
- package/src/markdown.ts +1 -4
- package/src/outbox.ts +4 -4
- package/src/plugin.ts +9 -10
- package/src/sender.ts +6 -6
- package/src/tool.ts +12 -7
- package/src/transport.ts +5 -5
- package/exports.ts +0 -2
- package/lib/exports.d.ts +0 -2
- package/lib/exports.js +0 -3
- package/lib/src/brand.d.ts +0 -10
- package/lib/src/brand.js +0 -10
- package/src/brand.ts +0 -14
package/package.json
CHANGED
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@databricks/appkit": "0.81.0",
|
|
30
|
-
"@dbx-tools/appkit": "^0.9.
|
|
31
|
-
"@dbx-tools/core": "^0.9.
|
|
32
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
33
|
-
"@dbx-tools/shared-email": "^0.9.
|
|
34
|
-
"@dbx-tools/shared-email-template": "^0.9.
|
|
30
|
+
"@dbx-tools/appkit": "^0.9.157",
|
|
31
|
+
"@dbx-tools/core": "^0.9.157",
|
|
32
|
+
"@dbx-tools/shared-core": "^0.9.157",
|
|
33
|
+
"@dbx-tools/shared-email": "^0.9.157",
|
|
34
|
+
"@dbx-tools/shared-email-template": "^0.9.157",
|
|
35
35
|
"@mastra/core": "1.71.0",
|
|
36
36
|
"@react-email/render": "^2.1.0",
|
|
37
37
|
"nodemailer": "^7.0.13",
|
|
@@ -49,54 +49,10 @@
|
|
|
49
49
|
"types": "./lib/index.d.ts",
|
|
50
50
|
"default": "./lib/index.js"
|
|
51
51
|
},
|
|
52
|
-
"./brand": {
|
|
53
|
-
"types": "./lib/src/brand.d.ts",
|
|
54
|
-
"default": "./lib/src/brand.js"
|
|
55
|
-
},
|
|
56
|
-
"./config": {
|
|
57
|
-
"types": "./lib/src/config.d.ts",
|
|
58
|
-
"default": "./lib/src/config.js"
|
|
59
|
-
},
|
|
60
|
-
"./defaults": {
|
|
61
|
-
"types": "./lib/src/defaults.d.ts",
|
|
62
|
-
"default": "./lib/src/defaults.js"
|
|
63
|
-
},
|
|
64
|
-
"./email-html": {
|
|
65
|
-
"types": "./lib/src/email-html.d.ts",
|
|
66
|
-
"default": "./lib/src/email-html.js"
|
|
67
|
-
},
|
|
68
|
-
"./markdown": {
|
|
69
|
-
"types": "./lib/src/markdown.d.ts",
|
|
70
|
-
"default": "./lib/src/markdown.js"
|
|
71
|
-
},
|
|
72
|
-
"./outbox": {
|
|
73
|
-
"types": "./lib/src/outbox.d.ts",
|
|
74
|
-
"default": "./lib/src/outbox.js"
|
|
75
|
-
},
|
|
76
|
-
"./plugin": {
|
|
77
|
-
"types": "./lib/src/plugin.d.ts",
|
|
78
|
-
"default": "./lib/src/plugin.js"
|
|
79
|
-
},
|
|
80
|
-
"./sender": {
|
|
81
|
-
"types": "./lib/src/sender.d.ts",
|
|
82
|
-
"default": "./lib/src/sender.js"
|
|
83
|
-
},
|
|
84
|
-
"./tool": {
|
|
85
|
-
"types": "./lib/src/tool.d.ts",
|
|
86
|
-
"default": "./lib/src/tool.js"
|
|
87
|
-
},
|
|
88
|
-
"./transport": {
|
|
89
|
-
"types": "./lib/src/transport.d.ts",
|
|
90
|
-
"default": "./lib/src/transport.js"
|
|
91
|
-
},
|
|
92
|
-
"./*": {
|
|
93
|
-
"types": "./lib/src/*/index.d.ts",
|
|
94
|
-
"default": "./lib/src/*/index.js"
|
|
95
|
-
},
|
|
96
52
|
"./package.json": "./package.json"
|
|
97
53
|
}
|
|
98
54
|
},
|
|
99
|
-
"version": "0.9.
|
|
55
|
+
"version": "0.9.157",
|
|
100
56
|
"types": "./lib/index.d.ts",
|
|
101
57
|
"dbxToolsConfig": {
|
|
102
58
|
"tags": [
|
|
@@ -109,56 +65,11 @@
|
|
|
109
65
|
"types": "./lib/index.d.ts",
|
|
110
66
|
"default": "./lib/index.js"
|
|
111
67
|
},
|
|
112
|
-
"./brand": {
|
|
113
|
-
"types": "./lib/src/brand.d.ts",
|
|
114
|
-
"default": "./lib/src/brand.js"
|
|
115
|
-
},
|
|
116
|
-
"./config": {
|
|
117
|
-
"types": "./lib/src/config.d.ts",
|
|
118
|
-
"default": "./lib/src/config.js"
|
|
119
|
-
},
|
|
120
|
-
"./defaults": {
|
|
121
|
-
"types": "./lib/src/defaults.d.ts",
|
|
122
|
-
"default": "./lib/src/defaults.js"
|
|
123
|
-
},
|
|
124
|
-
"./email-html": {
|
|
125
|
-
"types": "./lib/src/email-html.d.ts",
|
|
126
|
-
"default": "./lib/src/email-html.js"
|
|
127
|
-
},
|
|
128
|
-
"./markdown": {
|
|
129
|
-
"types": "./lib/src/markdown.d.ts",
|
|
130
|
-
"default": "./lib/src/markdown.js"
|
|
131
|
-
},
|
|
132
|
-
"./outbox": {
|
|
133
|
-
"types": "./lib/src/outbox.d.ts",
|
|
134
|
-
"default": "./lib/src/outbox.js"
|
|
135
|
-
},
|
|
136
|
-
"./plugin": {
|
|
137
|
-
"types": "./lib/src/plugin.d.ts",
|
|
138
|
-
"default": "./lib/src/plugin.js"
|
|
139
|
-
},
|
|
140
|
-
"./sender": {
|
|
141
|
-
"types": "./lib/src/sender.d.ts",
|
|
142
|
-
"default": "./lib/src/sender.js"
|
|
143
|
-
},
|
|
144
|
-
"./tool": {
|
|
145
|
-
"types": "./lib/src/tool.d.ts",
|
|
146
|
-
"default": "./lib/src/tool.js"
|
|
147
|
-
},
|
|
148
|
-
"./transport": {
|
|
149
|
-
"types": "./lib/src/transport.d.ts",
|
|
150
|
-
"default": "./lib/src/transport.js"
|
|
151
|
-
},
|
|
152
|
-
"./*": {
|
|
153
|
-
"types": "./lib/src/*/index.d.ts",
|
|
154
|
-
"default": "./lib/src/*/index.js"
|
|
155
|
-
},
|
|
156
68
|
"./package.json": "./package.json"
|
|
157
69
|
},
|
|
158
70
|
"files": [
|
|
159
|
-
"index
|
|
71
|
+
"index*.ts",
|
|
160
72
|
"src",
|
|
161
|
-
"exports.ts",
|
|
162
73
|
"lib"
|
|
163
74
|
],
|
|
164
75
|
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"bunx projen\"."
|
package/src/config.ts
CHANGED
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { resolve } from "node:path";
|
|
28
28
|
import { ConfigurationError, ValidationError, type BasePluginConfig } from "@databricks/appkit";
|
|
29
|
-
import { configUtils } from "@dbx-tools/core";
|
|
30
|
-
import {
|
|
29
|
+
import { configUtils, boolean, ENV_ONLY, text, string } from "@dbx-tools/core";
|
|
30
|
+
import { optional } from "@dbx-tools/shared-core";
|
|
31
|
+
import { defaultEmailBrand, type EmailBrand } from "@dbx-tools/shared-email-template";
|
|
31
32
|
import type { JSONSchema7 } from "json-schema";
|
|
32
|
-
import { defaultEmailBrand, type EmailBrand } from "./brand.ts";
|
|
33
33
|
import { isSenderAllowed, parseAllowedSenders, systemSenderAddress } from "./sender.ts";
|
|
34
34
|
|
|
35
35
|
/** SMTP submission port used when none is configured. */
|
|
@@ -271,16 +271,12 @@ export const EMAIL_CONFIG_SCHEMA: JSONSchema7 = {
|
|
|
271
271
|
|
|
272
272
|
/** Parse the `SMTP_SECURE` env / config flag, defaulting by port. */
|
|
273
273
|
function resolveSecure(flag: boolean | undefined, port: number): boolean {
|
|
274
|
-
return (
|
|
275
|
-
configUtils.boolean(flag, "SMTP_SECURE", configUtils.ENV_ONLY) ??
|
|
276
|
-
port === IMPLICIT_TLS_SMTP_PORT
|
|
277
|
-
);
|
|
274
|
+
return boolean(flag, "SMTP_SECURE", ENV_ONLY) ?? port === IMPLICIT_TLS_SMTP_PORT;
|
|
278
275
|
}
|
|
279
276
|
|
|
280
277
|
/** Parse the `EMAIL_SENDER_POLICY` env / config value, defaulting to deny-by-default. */
|
|
281
278
|
function resolveSenderPolicy(policy: SenderPolicy | undefined): SenderPolicy {
|
|
282
|
-
const raw =
|
|
283
|
-
policy ?? configUtils.text("EMAIL_SENDER_POLICY", configUtils.ENV_ONLY)?.toLowerCase();
|
|
279
|
+
const raw = policy ?? text("EMAIL_SENDER_POLICY", ENV_ONLY)?.toLowerCase();
|
|
284
280
|
if (raw === "unrestricted") return "unrestricted";
|
|
285
281
|
if (raw === undefined || raw === "" || raw === "allowlist") return "allowlist";
|
|
286
282
|
throw ValidationError.invalidValue("senderPolicy", raw, '"allowlist" or "unrestricted"');
|
|
@@ -313,7 +309,7 @@ function impliedSenderPatterns(sender: {
|
|
|
313
309
|
|
|
314
310
|
/** Whether `EMAIL_OUTBOX_MODE` explicitly opts into the file/outbox fallback. */
|
|
315
311
|
function isOutboxModeEnabled(): boolean {
|
|
316
|
-
return
|
|
312
|
+
return boolean(undefined, "EMAIL_OUTBOX_MODE", ENV_ONLY) ?? false;
|
|
317
313
|
}
|
|
318
314
|
|
|
319
315
|
const SMTP_REQUIRED_FIELDS = ["SMTP_HOST", "SMTP_USER", "SMTP_PASSWORD"] as const;
|
|
@@ -349,28 +345,24 @@ function missingSmtpFields(
|
|
|
349
345
|
*/
|
|
350
346
|
export function resolveEmailConfig(config: EmailPluginConfig = {}): ResolvedEmailConfig {
|
|
351
347
|
const smtp = config.smtp ?? {};
|
|
352
|
-
const host =
|
|
353
|
-
const user =
|
|
354
|
-
const pass =
|
|
355
|
-
const domain =
|
|
356
|
-
const from =
|
|
357
|
-
const systemFrom =
|
|
358
|
-
config.systemFrom,
|
|
359
|
-
"EMAIL_SYSTEM_FROM",
|
|
360
|
-
configUtils.ENV_ONLY,
|
|
361
|
-
);
|
|
348
|
+
const host = string(smtp.host, "SMTP_HOST", ENV_ONLY);
|
|
349
|
+
const user = string(smtp.user, "SMTP_USER", ENV_ONLY);
|
|
350
|
+
const pass = string(smtp.password, "SMTP_PASSWORD", ENV_ONLY);
|
|
351
|
+
const domain = string(config.domain, "EMAIL_DOMAIN", ENV_ONLY);
|
|
352
|
+
const from = string(config.from, "EMAIL_FROM", ENV_ONLY);
|
|
353
|
+
const systemFrom = string(config.systemFrom, "EMAIL_SYSTEM_FROM", ENV_ONLY);
|
|
362
354
|
const senderPolicy = resolveSenderPolicy(config.senderPolicy);
|
|
363
355
|
const configuredSenders = parseAllowedSenders(
|
|
364
|
-
config.allowedSenders ??
|
|
356
|
+
config.allowedSenders ?? text("EMAIL_ALLOWED_SENDERS", ENV_ONLY),
|
|
365
357
|
);
|
|
366
358
|
const allowedSenders =
|
|
367
359
|
configuredSenders.length > 0 || senderPolicy === "unrestricted"
|
|
368
360
|
? configuredSenders
|
|
369
361
|
: impliedSenderPatterns({ domain, from, systemFrom });
|
|
370
362
|
const sender: ResolvedSender = {
|
|
371
|
-
...
|
|
372
|
-
...
|
|
373
|
-
...
|
|
363
|
+
...optional("domain", domain),
|
|
364
|
+
...optional("from", from),
|
|
365
|
+
...optional("systemFrom", systemFrom),
|
|
374
366
|
allowedSenders,
|
|
375
367
|
senderPolicy,
|
|
376
368
|
brand: config.brand ?? defaultEmailBrand,
|
|
@@ -390,7 +382,7 @@ export function resolveEmailConfig(config: EmailPluginConfig = {}): ResolvedEmai
|
|
|
390
382
|
"Set EMAIL_DOMAIN to derive <user-local-part>@<domain> (and no-reply@<domain> for system mail), or EMAIL_FROM for a fixed address.",
|
|
391
383
|
);
|
|
392
384
|
}
|
|
393
|
-
const port = configUtils.port(smtp.port, "SMTP_PORT", DEFAULT_SMTP_PORT,
|
|
385
|
+
const port = configUtils.port(smtp.port, "SMTP_PORT", DEFAULT_SMTP_PORT, ENV_ONLY);
|
|
394
386
|
return {
|
|
395
387
|
mode: "smtp",
|
|
396
388
|
host: host!,
|
|
@@ -409,8 +401,7 @@ export function resolveEmailConfig(config: EmailPluginConfig = {}): ResolvedEmai
|
|
|
409
401
|
}
|
|
410
402
|
|
|
411
403
|
const outDir = resolve(
|
|
412
|
-
|
|
413
|
-
resolve(process.cwd(), "tmp"),
|
|
404
|
+
string(config.outDir, "EMAIL_OUTBOX_DIR", ENV_ONLY) ?? resolve(process.cwd(), "tmp"),
|
|
414
405
|
);
|
|
415
406
|
return { mode: "file", outDir, ...sender };
|
|
416
407
|
}
|
package/src/email-html.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/** Node rendering adapters for the shared React Email document. @module */
|
|
2
|
-
import { stringUtils } from "@dbx-tools/shared-core";
|
|
3
2
|
import { EmailDocument, type EmailDocumentProps } from "@dbx-tools/shared-email-template";
|
|
4
3
|
import { render } from "@react-email/render";
|
|
5
4
|
import { createElement } from "react";
|
|
6
5
|
|
|
7
|
-
/** Escape HTML-significant characters (re-exported from shared-core). */
|
|
8
|
-
export const escapeHtml = stringUtils.escapeHtml;
|
|
9
|
-
|
|
10
6
|
/** Options accepted by the shared React Email document. */
|
|
11
7
|
export type EmailHtmlOptions = EmailDocumentProps;
|
|
12
8
|
|
package/src/markdown.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Node rendering helper backed by the shared React Email body. @module */
|
|
2
2
|
import { EmailBody, normalizeEmailMarkdown } from "@dbx-tools/shared-email-template";
|
|
3
3
|
import { render } from "@react-email/render";
|
|
4
4
|
import { createElement } from "react";
|
|
5
5
|
|
|
6
|
-
/** Normalize indentation in authored content. */
|
|
7
|
-
export const normalizeMarkdown = normalizeEmailMarkdown;
|
|
8
|
-
|
|
9
6
|
/** Render a standalone message body through React Email. */
|
|
10
7
|
export async function markdownToHtml(body: string): Promise<string> {
|
|
11
8
|
return render(createElement(EmailBody, { body: normalizeEmailMarkdown(body) }), {
|
package/src/outbox.ts
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
|
|
16
16
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
17
17
|
import { join, resolve } from "node:path";
|
|
18
|
-
import {
|
|
18
|
+
import { toSlugWithOptions } from "@dbx-tools/shared-core";
|
|
19
19
|
import type { EmailMessage } from "@dbx-tools/shared-email";
|
|
20
|
-
import type { EmailBrand } from "
|
|
20
|
+
import type { EmailBrand } from "@dbx-tools/shared-email-template";
|
|
21
21
|
import { renderEmailHtml, type EmailHtmlOptions } from "./email-html.ts";
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -28,7 +28,7 @@ const SUBJECT_SLUG_MAX_LENGTH = 48;
|
|
|
28
28
|
|
|
29
29
|
/** Filesystem-safe slug of the subject for the file name. */
|
|
30
30
|
function subjectSlug(subject: string): string {
|
|
31
|
-
return
|
|
31
|
+
return toSlugWithOptions({ maxLength: SUBJECT_SLUG_MAX_LENGTH }, subject) || "email";
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/** The envelope rows shown above the body in the preview file. */
|
|
@@ -55,7 +55,7 @@ export async function writeOutboxEmail(
|
|
|
55
55
|
from: string,
|
|
56
56
|
dir: string,
|
|
57
57
|
brand?: EmailBrand,
|
|
58
|
-
presentation?: Pick<EmailHtmlOptions, "heading" | "preview"
|
|
58
|
+
presentation?: Partial<Pick<EmailHtmlOptions, "heading" | "preview">>,
|
|
59
59
|
): Promise<string> {
|
|
60
60
|
const folder = resolve(dir, from);
|
|
61
61
|
await mkdir(folder, { recursive: true });
|
package/src/plugin.ts
CHANGED
|
@@ -37,15 +37,15 @@ import {
|
|
|
37
37
|
type PluginManifest,
|
|
38
38
|
} from "@databricks/appkit";
|
|
39
39
|
import { defineTool, type ToolRegistry } from "@databricks/appkit/beta";
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
40
|
+
import { ToolRegistryPlugin, getBrandContext } from "@dbx-tools/appkit";
|
|
41
|
+
import { log, toError, trimToNull, ACCESS_TOKEN_HEADER } from "@dbx-tools/shared-core";
|
|
42
42
|
import {
|
|
43
|
-
email as sharedEmail,
|
|
44
43
|
type EmailMessage,
|
|
45
44
|
type EmailResult,
|
|
46
45
|
type EmailSenders,
|
|
46
|
+
emailMessageSchema,
|
|
47
47
|
} from "@dbx-tools/shared-email";
|
|
48
|
-
import { emailBrandFromContext } from "
|
|
48
|
+
import { emailBrandFromContext } from "@dbx-tools/shared-email-template";
|
|
49
49
|
import { EMAIL_CONFIG_SCHEMA, type EmailPluginConfig } from "./config.ts";
|
|
50
50
|
import { EMAIL_SENDERS_SETTINGS, EMAIL_VERIFY_SETTINGS } from "./defaults.ts";
|
|
51
51
|
import { isSenderAllowed, listSenderOptions, resolveSenderAddress } from "./sender.ts";
|
|
@@ -116,11 +116,10 @@ export class EmailPlugin extends ToolRegistryPlugin<EmailPluginConfig> {
|
|
|
116
116
|
protected readonly toolRegistry: ToolRegistry = {
|
|
117
117
|
[SEND_TOOL]: defineTool({
|
|
118
118
|
description: SEND_EMAIL_DESCRIPTION,
|
|
119
|
-
schema:
|
|
119
|
+
schema: emailMessageSchema,
|
|
120
120
|
annotations: { effect: "write", requiresUserContext: true },
|
|
121
121
|
autoInheritable: false,
|
|
122
|
-
execute: async (args, signal) =>
|
|
123
|
-
this.send(sharedEmail.emailMessageSchema.parse(args), undefined, signal),
|
|
122
|
+
execute: async (args, signal) => this.send(emailMessageSchema.parse(args), undefined, signal),
|
|
124
123
|
}),
|
|
125
124
|
};
|
|
126
125
|
|
|
@@ -138,7 +137,7 @@ export class EmailPlugin extends ToolRegistryPlugin<EmailPluginConfig> {
|
|
|
138
137
|
override async setup(): Promise<void> {
|
|
139
138
|
const { transporter, config } = getEmailRuntime({
|
|
140
139
|
...this.config,
|
|
141
|
-
brand: this.config.brand ?? emailBrandFromContext(
|
|
140
|
+
brand: this.config.brand ?? emailBrandFromContext(getBrandContext()),
|
|
142
141
|
});
|
|
143
142
|
setEmailExecutor((fn, settings) => this.execute(fn, settings));
|
|
144
143
|
const policy = {
|
|
@@ -164,7 +163,7 @@ export class EmailPlugin extends ToolRegistryPlugin<EmailPluginConfig> {
|
|
|
164
163
|
host: config.host,
|
|
165
164
|
port: config.port,
|
|
166
165
|
status: verified.status,
|
|
167
|
-
error:
|
|
166
|
+
error: toError(verified.message),
|
|
168
167
|
});
|
|
169
168
|
throw ConfigurationError.invalidConnection(
|
|
170
169
|
"SMTP",
|
|
@@ -222,7 +221,7 @@ export class EmailPlugin extends ToolRegistryPlugin<EmailPluginConfig> {
|
|
|
222
221
|
method: "get",
|
|
223
222
|
path: SENDERS_ROUTE,
|
|
224
223
|
handler: async (req, res) => {
|
|
225
|
-
const oboToken =
|
|
224
|
+
const oboToken = trimToNull(req.header(ACCESS_TOKEN_HEADER));
|
|
226
225
|
const scoped = oboToken === null ? this : this.asUser(req);
|
|
227
226
|
const result = await scoped.executeListSenders();
|
|
228
227
|
if (!result.ok) {
|
package/src/sender.ts
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { ConfigurationError, ValidationError } from "@databricks/appkit";
|
|
31
|
-
import { log,
|
|
31
|
+
import { log, parseEmails, trimToNull } from "@dbx-tools/shared-core";
|
|
32
32
|
|
|
33
33
|
import type { ResolvedEmailConfig, ResolvedSender } from "./config.ts";
|
|
34
34
|
|
|
@@ -60,7 +60,7 @@ export function deriveSenderAddress(userEmail: string | undefined, domain: strin
|
|
|
60
60
|
* restriction".
|
|
61
61
|
*/
|
|
62
62
|
export function parseAllowedSenders(raw: string | string[] | undefined): string[] {
|
|
63
|
-
return
|
|
63
|
+
return parseEmails(raw, { lowercase: true });
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/** The `@domain` suffix a wildcard / bare-domain pattern matches, else null. */
|
|
@@ -132,11 +132,11 @@ type SenderSource = Pick<ResolvedSender, "systemFrom" | "domain" | "from">;
|
|
|
132
132
|
* result into the sender allow-list before any send happens.
|
|
133
133
|
*/
|
|
134
134
|
export function systemSenderAddress(source: SenderSource): string | undefined {
|
|
135
|
-
const explicit =
|
|
135
|
+
const explicit = trimToNull(source.systemFrom);
|
|
136
136
|
if (explicit) return explicit;
|
|
137
|
-
const domain =
|
|
137
|
+
const domain = trimToNull(source.domain);
|
|
138
138
|
if (domain) return `${SYSTEM_SENDER_LOCAL_PART}@${domain}`;
|
|
139
|
-
return
|
|
139
|
+
return trimToNull(source.from) ?? undefined;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
/**
|
|
@@ -166,7 +166,7 @@ export function resolveSenderAddress(
|
|
|
166
166
|
config: ResolvedEmailConfig,
|
|
167
167
|
userEmail: string | undefined,
|
|
168
168
|
): string {
|
|
169
|
-
const email =
|
|
169
|
+
const email = trimToNull(userEmail);
|
|
170
170
|
if (!email) return resolveSystemSenderAddress(config);
|
|
171
171
|
if (config.from) return config.from;
|
|
172
172
|
if (config.domain) return deriveSenderAddress(email, config.domain);
|
package/src/tool.ts
CHANGED
|
@@ -18,8 +18,13 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { getExecutionContext } from "@databricks/appkit";
|
|
21
|
-
import { log,
|
|
22
|
-
import {
|
|
21
|
+
import { log, toDescription } from "@dbx-tools/shared-core";
|
|
22
|
+
import {
|
|
23
|
+
type EmailMessage,
|
|
24
|
+
type EmailResult,
|
|
25
|
+
emailMessageSchema,
|
|
26
|
+
emailResultSchema,
|
|
27
|
+
} from "@dbx-tools/shared-email";
|
|
23
28
|
import { createTool, type ToolAction } from "@mastra/core/tools";
|
|
24
29
|
import { resolveSenderAddress } from "./sender.ts";
|
|
25
30
|
import { getEmailRuntime, sendEmail } from "./transport.ts";
|
|
@@ -31,7 +36,7 @@ const logger = log.logger("email/tool/send-email");
|
|
|
31
36
|
* {@link emailTool} and the AppKit `email.send` tool so both agents get the
|
|
32
37
|
* same guidance about approval and scope.
|
|
33
38
|
*/
|
|
34
|
-
export const SEND_EMAIL_DESCRIPTION =
|
|
39
|
+
export const SEND_EMAIL_DESCRIPTION = toDescription(`
|
|
35
40
|
Send an email on the user's behalf. Pass one or more recipient
|
|
36
41
|
addresses (with optional cc / bcc and file attachments), a subject,
|
|
37
42
|
and a body; the configured approval policy runs before it goes out.
|
|
@@ -55,7 +60,7 @@ export interface EmailToolOptions {
|
|
|
55
60
|
* Use a function or Classifier-backed policy to allow low-risk calls while
|
|
56
61
|
* retaining human review for uncertain ones.
|
|
57
62
|
*/
|
|
58
|
-
requireApproval?: ToolAction<
|
|
63
|
+
requireApproval?: ToolAction<EmailMessage, EmailResult>["requireApproval"];
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
/**
|
|
@@ -78,11 +83,11 @@ export function emailTool(opts: EmailToolOptions = {}) {
|
|
|
78
83
|
return createTool({
|
|
79
84
|
id: opts.id ?? "send_email",
|
|
80
85
|
description: SEND_EMAIL_DESCRIPTION,
|
|
81
|
-
inputSchema:
|
|
82
|
-
outputSchema:
|
|
86
|
+
inputSchema: emailMessageSchema,
|
|
87
|
+
outputSchema: emailResultSchema,
|
|
83
88
|
requireApproval: opts.requireApproval ?? true,
|
|
84
89
|
execute: async (input, context) => {
|
|
85
|
-
const message =
|
|
90
|
+
const message = emailMessageSchema.parse(input);
|
|
86
91
|
const { config } = getEmailRuntime();
|
|
87
92
|
const ctx = getExecutionContext();
|
|
88
93
|
const userEmail = "isUserContext" in ctx ? ctx.userEmail : undefined;
|
package/src/transport.ts
CHANGED
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { ConfigurationError, ValidationError, type ExecutionResult } from "@databricks/appkit";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
26
|
+
import { runPluginExecution } from "@dbx-tools/appkit";
|
|
27
|
+
import { log, directExecutor } from "@dbx-tools/shared-core";
|
|
28
28
|
import type { EmailAttachment, EmailMessage, EmailResult } from "@dbx-tools/shared-email";
|
|
29
|
+
import type { EmailBrand } from "@dbx-tools/shared-email-template";
|
|
29
30
|
import nodemailer, { type SendMailOptions, type Transporter } from "nodemailer";
|
|
30
|
-
import type { EmailBrand } from "./brand.ts";
|
|
31
31
|
import { resolveEmailConfig, type EmailPluginConfig, type ResolvedEmailConfig } from "./config.ts";
|
|
32
32
|
import {
|
|
33
33
|
EMAIL_SEND_SETTINGS,
|
|
@@ -66,7 +66,7 @@ export interface EmailRuntime {
|
|
|
66
66
|
* directly, mapping a throw onto the same {@link ExecutionResult} shape so
|
|
67
67
|
* call sites branch on `ok` either way.
|
|
68
68
|
*/
|
|
69
|
-
const directExecute =
|
|
69
|
+
const directExecute = directExecutor<EmailExecutionSettings>();
|
|
70
70
|
|
|
71
71
|
let runtime: EmailRuntime | undefined;
|
|
72
72
|
|
|
@@ -143,7 +143,7 @@ export async function executeWrite<T>(
|
|
|
143
143
|
signal?: AbortSignal,
|
|
144
144
|
): Promise<T> {
|
|
145
145
|
const { execute } = getEmailRuntime();
|
|
146
|
-
return
|
|
146
|
+
return runPluginExecution({
|
|
147
147
|
plugin: "email",
|
|
148
148
|
logger,
|
|
149
149
|
operation,
|
package/exports.ts
DELETED
package/lib/exports.d.ts
DELETED
package/lib/exports.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
export { defaultEmailBrand, emailBrandFromContext } from "./src/brand.js";
|
|
2
|
-
export { emailTool } from "./src/tool.js";
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL2V4cG9ydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHFCQUFxQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IGRlZmF1bHRFbWFpbEJyYW5kLCBlbWFpbEJyYW5kRnJvbUNvbnRleHQgfSBmcm9tIFwiLi9zcmMvYnJhbmQudHNcIjtcbmV4cG9ydCB7IGVtYWlsVG9vbCB9IGZyb20gXCIuL3NyYy90b29sLnRzXCI7XG4iXX0=
|
package/lib/src/brand.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Email brand compatibility exports.
|
|
3
|
-
*
|
|
4
|
-
* The universal brand contract and defaults live with the shared React Email
|
|
5
|
-
* template so Node delivery and browser previews cannot drift.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
export { defaultEmailBrand, emailBrandFromContext, resolveEmailBrand, } from "@dbx-tools/shared-email-template";
|
|
10
|
-
export type { EmailBrand, ResolvedEmailBrand } from "@dbx-tools/shared-email-template";
|
package/lib/src/brand.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Email brand compatibility exports.
|
|
3
|
-
*
|
|
4
|
-
* The universal brand contract and defaults live with the shared React Email
|
|
5
|
-
* template so Node delivery and browser previews cannot drift.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
export { defaultEmailBrand, emailBrandFromContext, resolveEmailBrand, } from "@dbx-tools/shared-email-template";
|
|
10
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJhbmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnJhbmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUNILE9BQU8sRUFDTCxpQkFBaUIsRUFDakIscUJBQXFCLEVBQ3JCLGlCQUFpQixHQUNsQixNQUFNLGtDQUFrQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBFbWFpbCBicmFuZCBjb21wYXRpYmlsaXR5IGV4cG9ydHMuXG4gKlxuICogVGhlIHVuaXZlcnNhbCBicmFuZCBjb250cmFjdCBhbmQgZGVmYXVsdHMgbGl2ZSB3aXRoIHRoZSBzaGFyZWQgUmVhY3QgRW1haWxcbiAqIHRlbXBsYXRlIHNvIE5vZGUgZGVsaXZlcnkgYW5kIGJyb3dzZXIgcHJldmlld3MgY2Fubm90IGRyaWZ0LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuZXhwb3J0IHtcbiAgZGVmYXVsdEVtYWlsQnJhbmQsXG4gIGVtYWlsQnJhbmRGcm9tQ29udGV4dCxcbiAgcmVzb2x2ZUVtYWlsQnJhbmQsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1lbWFpbC10ZW1wbGF0ZVwiO1xuZXhwb3J0IHR5cGUgeyBFbWFpbEJyYW5kLCBSZXNvbHZlZEVtYWlsQnJhbmQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZW1haWwtdGVtcGxhdGVcIjtcbiJdfQ==
|
package/src/brand.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Email brand compatibility exports.
|
|
3
|
-
*
|
|
4
|
-
* The universal brand contract and defaults live with the shared React Email
|
|
5
|
-
* template so Node delivery and browser previews cannot drift.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
export {
|
|
10
|
-
defaultEmailBrand,
|
|
11
|
-
emailBrandFromContext,
|
|
12
|
-
resolveEmailBrand,
|
|
13
|
-
} from "@dbx-tools/shared-email-template";
|
|
14
|
-
export type { EmailBrand, ResolvedEmailBrand } from "@dbx-tools/shared-email-template";
|