|
1 | 1 | import { requireClient } from "../../client"; |
2 | | -import { |
3 | | - BatchSendEmailToolRequest, |
4 | | - BatchSendEmailBase, |
5 | | - BatchSendEmailRequest, |
6 | | -} from "../../types/mailtrap"; |
7 | | -import { |
8 | | - buildFromAddress, |
9 | | - normalizeAddressList, |
10 | | - normalizeToRecipients, |
11 | | - toMailtrapAddress, |
12 | | -} from "../../utils/mailtrapAddresses"; |
| 2 | +import { BatchSendEmailToolRequest } from "../../types/mailtrap"; |
| 3 | +import buildBatchPayload from "./buildBatchPayload"; |
13 | 4 | import { |
14 | 5 | buildErrorResponse, |
15 | 6 | buildSuccessResponse, |
16 | 7 | ToolResponse, |
17 | 8 | } from "../utils/responses"; |
18 | 9 |
|
19 | | -const { DEFAULT_FROM_EMAIL } = process.env; |
20 | | - |
21 | | -function ensureNoForbiddenFields( |
22 | | - source: BatchSendEmailBase | BatchSendEmailRequest, |
23 | | - scope: string |
24 | | -): void { |
25 | | - if (source.template_uuid === undefined) { |
26 | | - if (source.template_variables !== undefined) { |
27 | | - throw new Error( |
28 | | - `${scope}: 'template_variables' can only be used together with 'template_uuid'` |
29 | | - ); |
30 | | - } |
31 | | - return; |
32 | | - } |
33 | | - const forbidden = ( |
34 | | - [ |
35 | | - ["subject", source.subject], |
36 | | - ["text", source.text], |
37 | | - ["html", source.html], |
38 | | - ["category", source.category], |
39 | | - ] as const |
40 | | - ).filter(([, value]) => value !== undefined && value !== ""); |
41 | | - if (forbidden.length > 0) { |
42 | | - const fields = forbidden.map(([name]) => name).join(", "); |
43 | | - throw new Error( |
44 | | - `${scope}: when 'template_uuid' is set, the following fields must be omitted: ${fields}` |
45 | | - ); |
46 | | - } |
47 | | -} |
48 | | - |
49 | | -async function batchSendTransactionalEmail({ |
50 | | - base, |
51 | | - requests, |
52 | | -}: BatchSendEmailToolRequest): Promise<ToolResponse> { |
| 10 | +async function batchSendTransactionalEmail( |
| 11 | + body: BatchSendEmailToolRequest |
| 12 | +): Promise<ToolResponse> { |
53 | 13 | try { |
54 | 14 | const mailtrap = requireClient("batch sending transactional email", { |
55 | 15 | requireAccountId: false, |
56 | 16 | }); |
57 | 17 |
|
58 | | - if (!requests || requests.length === 0) { |
59 | | - throw new Error("'requests' must contain at least one entry"); |
60 | | - } |
61 | | - |
62 | | - if (base) ensureNoForbiddenFields(base, "base"); |
63 | | - requests.forEach((req, i) => { |
64 | | - // Effective config = base merged with the request's overrides. A request |
65 | | - // using `template_uuid` cannot also set inline content. |
66 | | - const merged: BatchSendEmailRequest = { |
67 | | - ...(base ?? {}), |
68 | | - ...req, |
69 | | - } as BatchSendEmailRequest; |
70 | | - ensureNoForbiddenFields(merged, `requests[${i}]`); |
71 | | - |
72 | | - const hasTemplate = merged.template_uuid !== undefined; |
73 | | - const hasInlineBody = |
74 | | - (merged.subject !== undefined && merged.subject !== "") || |
75 | | - (merged.text !== undefined && merged.text !== "") || |
76 | | - (merged.html !== undefined && merged.html !== ""); |
77 | | - if (!hasTemplate) { |
78 | | - if (!merged.subject) { |
79 | | - throw new Error( |
80 | | - `requests[${i}]: 'subject' is required (either on base or per-request) when not using a template` |
81 | | - ); |
82 | | - } |
83 | | - if (!merged.html && !merged.text) { |
84 | | - throw new Error( |
85 | | - `requests[${i}]: either 'html' or 'text' body is required when not using a template` |
86 | | - ); |
87 | | - } |
88 | | - } else if (hasInlineBody && !merged.template_uuid) { |
89 | | - // Defensive: should be unreachable after ensureNoForbiddenFields. |
90 | | - throw new Error( |
91 | | - `requests[${i}]: cannot mix 'template_uuid' with inline content` |
92 | | - ); |
93 | | - } |
94 | | - }); |
95 | | - |
96 | | - const fromAddress = buildFromAddress(base?.from, DEFAULT_FROM_EMAIL); |
97 | | - |
98 | | - const sdkBase: Record<string, unknown> = { from: fromAddress }; |
99 | | - if (base?.reply_to) sdkBase.reply_to = toMailtrapAddress(base.reply_to); |
100 | | - if (base?.subject !== undefined) sdkBase.subject = base.subject; |
101 | | - if (base?.text !== undefined) sdkBase.text = base.text; |
102 | | - if (base?.html !== undefined) sdkBase.html = base.html; |
103 | | - if (base?.category !== undefined) sdkBase.category = base.category; |
104 | | - if (base?.template_uuid !== undefined) |
105 | | - sdkBase.template_uuid = base.template_uuid; |
106 | | - if (base?.template_variables !== undefined) |
107 | | - sdkBase.template_variables = base.template_variables; |
108 | | - if (base?.custom_variables !== undefined) |
109 | | - sdkBase.custom_variables = base.custom_variables; |
110 | | - if (base?.headers !== undefined) sdkBase.headers = base.headers; |
111 | | - |
112 | | - const sdkRequests = requests.map((req, i) => { |
113 | | - const toAddresses = |
114 | | - req.to !== undefined ? normalizeToRecipients(req.to) : []; |
115 | | - const ccAddresses = |
116 | | - req.cc && req.cc.length > 0 ? normalizeAddressList(req.cc) : []; |
117 | | - const bccAddresses = |
118 | | - req.bcc && req.bcc.length > 0 ? normalizeAddressList(req.bcc) : []; |
| 18 | + const payload = buildBatchPayload(body); |
119 | 19 |
|
120 | | - if (toAddresses.length + ccAddresses.length + bccAddresses.length === 0) { |
121 | | - throw new Error( |
122 | | - `requests[${i}]: provide at least one recipient via 'to', 'cc', or 'bcc'` |
123 | | - ); |
124 | | - } |
125 | | - |
126 | | - const r: Record<string, unknown> = { |
127 | | - to: toAddresses, |
128 | | - }; |
129 | | - if (ccAddresses.length > 0) r.cc = ccAddresses; |
130 | | - if (bccAddresses.length > 0) r.bcc = bccAddresses; |
131 | | - if (req.reply_to) r.reply_to = [toMailtrapAddress(req.reply_to)]; |
132 | | - if (req.subject !== undefined) r.subject = req.subject; |
133 | | - if (req.text !== undefined) r.text = req.text; |
134 | | - if (req.html !== undefined) r.html = req.html; |
135 | | - if (req.category !== undefined) r.category = req.category; |
136 | | - if (req.template_uuid !== undefined) r.template_uuid = req.template_uuid; |
137 | | - if (req.template_variables !== undefined) |
138 | | - r.template_variables = req.template_variables; |
139 | | - if (req.custom_variables !== undefined) |
140 | | - r.custom_variables = req.custom_variables; |
141 | | - if (req.headers !== undefined) r.headers = req.headers; |
142 | | - return r; |
143 | | - }); |
144 | | - |
145 | | - const response = await mailtrap.batchSend({ |
146 | | - base: sdkBase, |
147 | | - requests: sdkRequests, |
148 | | - } as unknown as Parameters<typeof mailtrap.batchSend>[0]); |
| 20 | + const response = await mailtrap.batchSend( |
| 21 | + payload as unknown as Parameters<typeof mailtrap.batchSend>[0] |
| 22 | + ); |
149 | 23 |
|
150 | 24 | return buildSuccessResponse(JSON.stringify(response, null, 2)); |
151 | 25 | } catch (error) { |
|
0 commit comments