n8n-nodes-resend 2.6.2 → 2.6.4

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 (46) hide show
  1. package/README.md +1 -0
  2. package/dist/credentials/ResendApi.credentials.d.ts +2 -2
  3. package/dist/credentials/ResendOAuth2Api.credentials.d.ts +2 -2
  4. package/dist/credentials/ResendWebhookSigningSecretApi.credentials.d.ts +1 -1
  5. package/dist/nodes/Resend/Resend.node.d.ts +5 -3
  6. package/dist/nodes/Resend/Resend.node.js +14 -5
  7. package/dist/nodes/Resend/ResendTrigger.node.d.ts +13 -1
  8. package/dist/nodes/Resend/ResendTrigger.node.js +111 -6
  9. package/dist/nodes/Resend/actions/account/index.js +1 -1
  10. package/dist/nodes/Resend/actions/domain/listTrackingDomains.operation.js +2 -2
  11. package/dist/nodes/Resend/actions/email/send.operation.js +1 -1
  12. package/dist/nodes/Resend/actions/email/sendAndWait.operation.d.ts +1 -1
  13. package/dist/nodes/Resend/actions/email/sendAndWait.operation.js +1 -1
  14. package/dist/nodes/Resend/actions/email/sendBatch.operation.js +17 -4
  15. package/dist/nodes/Resend/actions/router.js +4 -1
  16. package/dist/nodes/Resend/actions/suppression/batchAdd.operation.d.ts +8 -0
  17. package/dist/nodes/Resend/actions/suppression/batchAdd.operation.js +41 -0
  18. package/dist/nodes/Resend/actions/suppression/batchRemove.operation.d.ts +8 -0
  19. package/dist/nodes/Resend/actions/suppression/batchRemove.operation.js +80 -0
  20. package/dist/nodes/Resend/actions/suppression/create.operation.d.ts +8 -0
  21. package/dist/nodes/Resend/actions/suppression/create.operation.js +37 -0
  22. package/dist/nodes/Resend/actions/suppression/delete.operation.d.ts +8 -0
  23. package/dist/nodes/Resend/actions/suppression/delete.operation.js +37 -0
  24. package/dist/nodes/Resend/actions/suppression/execute.d.ts +4 -0
  25. package/dist/nodes/Resend/actions/suppression/execute.js +18 -0
  26. package/dist/nodes/Resend/actions/suppression/get.operation.d.ts +8 -0
  27. package/dist/nodes/Resend/actions/suppression/get.operation.js +37 -0
  28. package/dist/nodes/Resend/actions/suppression/index.d.ts +13 -0
  29. package/dist/nodes/Resend/actions/suppression/index.js +122 -0
  30. package/dist/nodes/Resend/actions/suppression/list.operation.d.ts +8 -0
  31. package/dist/nodes/Resend/actions/suppression/list.operation.js +83 -0
  32. package/dist/nodes/Resend/actions/workflow/listRunSteps.operation.js +2 -2
  33. package/dist/nodes/Resend/actions/workflow/listRuns.operation.js +2 -2
  34. package/dist/nodes/Resend/methods/index.d.ts +3 -1
  35. package/dist/nodes/Resend/methods/index.js +35 -33
  36. package/dist/nodes/Resend/transport/index.d.ts +3 -2
  37. package/dist/nodes/Resend/transport/index.js +9 -3
  38. package/dist/nodes/Resend/utils/dynamicFields.d.ts +22 -20
  39. package/dist/nodes/Resend/utils/dynamicFields.js +2 -61
  40. package/dist/nodes/Resend/utils/sendAndWait/email-templates.d.ts +1 -3
  41. package/dist/nodes/Resend/utils/sendAndWait/email-templates.js +0 -10
  42. package/dist/nodes/Resend/utils/sendAndWait/index.d.ts +2 -2
  43. package/dist/nodes/Resend/utils/sendAndWait/index.js +0 -2
  44. package/dist/nodes/Resend/utils/sendAndWait/utils.d.ts +2 -2
  45. package/dist/nodes/Resend/utils/sendAndWait/utils.js +19 -15
  46. package/package.json +10 -5
package/README.md CHANGED
@@ -45,6 +45,7 @@ The table below shows which endpoints are currently implemented:
45
45
  | **Contacts** | `/contacts` | ✅ Full | Create, List, Get, Update, Delete, Add to Segment, List Segments, Remove from Segment, Get Topics, Update Topics |
46
46
  | **Broadcasts** | `/broadcasts` | ✅ Full | Create, List, Get, Update, Delete, Send |
47
47
  | **Segments** | `/segments` | ✅ Full | Create, List, Get, Delete |
48
+ | **Suppressions** | `/suppressions` | ✅ Full | Create, List, Get, Delete, Batch Add, Batch Remove |
48
49
  | **Topics** | `/topics` | ✅ Full | Create, List, Get, Update, Delete |
49
50
  | **Contact Properties** | `/contact-properties` | ✅ Full | Create, List, Get, Update, Delete |
50
51
  | **Webhooks** | `/webhooks` | ✅ Full | Create, List, Get, Update, Delete |
@@ -5,8 +5,8 @@ declare class ResendApi implements ICredentialType {
5
5
  displayName: string;
6
6
  documentationUrl: string;
7
7
  icon: {
8
- readonly light: 'file:resend-icon-black.svg';
9
- readonly dark: 'file:resend-icon-white.svg';
8
+ readonly light: "file:resend-icon-black.svg";
9
+ readonly dark: "file:resend-icon-white.svg";
10
10
  };
11
11
  properties: INodeProperties[];
12
12
  authenticate: IAuthenticateGeneric;
@@ -6,8 +6,8 @@ declare class ResendOAuth2Api implements ICredentialType {
6
6
  displayName: string;
7
7
  documentationUrl: string;
8
8
  icon: {
9
- readonly light: 'file:resend-icon-black.svg';
10
- readonly dark: 'file:resend-icon-white.svg';
9
+ readonly light: "file:resend-icon-black.svg";
10
+ readonly dark: "file:resend-icon-white.svg";
11
11
  };
12
12
  properties: INodeProperties[];
13
13
  }
@@ -4,7 +4,7 @@ declare class ResendWebhookSigningSecretApi implements ICredentialType {
4
4
  name: string;
5
5
  displayName: string;
6
6
  documentationUrl: string;
7
- icon: 'file:resend.svg';
7
+ icon: "file:resend.svg";
8
8
  properties: INodeProperties[];
9
9
  }
10
10
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { router } from "./actions/router.js";
2
- import { getBroadcasts, getContactProperties, getContacts, getDomains, getEmails, getReceivedEmails, getSegments, getTemplateVariables, getTemplates, getTopics, getWebhooks } from "./methods/index.js";
2
+ import { getBroadcasts, getContactProperties, getContacts, getDomains, getEmails, getReceivedEmails, getSegments, getSuppressions, getTemplateVariables, getTemplates, getTopics, getWebhooks } from "./methods/index.js";
3
3
  import { INodeType, INodeTypeDescription, IWebhookFunctions } from "n8n-workflow";
4
4
  //#region nodes/Resend/Resend.node.d.ts
5
5
  declare class Resend implements INodeType {
@@ -13,6 +13,7 @@ declare class Resend implements INodeType {
13
13
  getEmails: typeof getEmails;
14
14
  getReceivedEmails: typeof getReceivedEmails;
15
15
  getSegments: typeof getSegments;
16
+ getSuppressions: typeof getSuppressions;
16
17
  getTemplateVariables: typeof getTemplateVariables;
17
18
  getTemplates: typeof getTemplates;
18
19
  getTopics: typeof getTopics;
@@ -26,6 +27,7 @@ declare class Resend implements INodeType {
26
27
  getEmails: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
27
28
  getReceivedEmails: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
28
29
  getSegments: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
30
+ getSuppressions: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
29
31
  getTemplates: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
30
32
  getTemplateVariables: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
31
33
  getTopics: (this: import("n8n-workflow").ILoadOptionsFunctions, filter?: string) => Promise<import("n8n-workflow").INodeListSearchResult>;
@@ -37,7 +39,6 @@ declare class Resend implements INodeType {
37
39
  webhookResponse?: undefined;
38
40
  workflowData?: undefined;
39
41
  } | {
40
- noWebhookResponse?: undefined;
41
42
  webhookResponse: undefined;
42
43
  workflowData: {
43
44
  json: {
@@ -46,8 +47,8 @@ declare class Resend implements INodeType {
46
47
  };
47
48
  };
48
49
  }[][];
49
- } | {
50
50
  noWebhookResponse?: undefined;
51
+ } | {
51
52
  webhookResponse: undefined;
52
53
  workflowData: {
53
54
  json: {
@@ -56,6 +57,7 @@ declare class Resend implements INodeType {
56
57
  };
57
58
  };
58
59
  }[][];
60
+ noWebhookResponse?: undefined;
59
61
  }>;
60
62
  execute: typeof router;
61
63
  }
@@ -12,6 +12,7 @@ const require_nodes_Resend_actions_event_index = require("./actions/event/index.
12
12
  const require_nodes_Resend_actions_log_index = require("./actions/log/index.js");
13
13
  const require_nodes_Resend_actions_receivingEmail_index = require("./actions/receivingEmail/index.js");
14
14
  const require_nodes_Resend_actions_segment_index = require("./actions/segment/index.js");
15
+ const require_nodes_Resend_actions_suppression_index = require("./actions/suppression/index.js");
15
16
  const require_nodes_Resend_actions_template_index = require("./actions/template/index.js");
16
17
  const require_nodes_Resend_actions_topic_index = require("./actions/topic/index.js");
17
18
  const require_nodes_Resend_actions_webhook_index = require("./actions/webhook/index.js");
@@ -33,7 +34,7 @@ var Resend = class {
33
34
  version: 1,
34
35
  usableAsTool: true,
35
36
  description: "Send emails, manage contacts, create broadcasts, handle templates, domains, segments, topics, and webhooks using the Resend email platform",
36
- subtitle: "={{(() => { const resourceLabels = { broadcasts: \"broadcast\", contacts: \"contact\", contactProperties: \"contact property\", domains: \"domain\", email: \"email\", logs: \"log\", receivingEmails: \"received email\", workflows: \"workflow\", events: \"event\", segments: \"segment\", templates: \"template\", topics: \"topic\", webhooks: \"webhook\" }; const operationLabels = { retrieve: \"get\", sendBatch: \"send batch\", listAttachments: \"list attachments\", getAttachment: \"get attachment\", addToSegment: \"add to segment\", listSegments: \"list segments\", removeFromSegment: \"remove from segment\", getTopics: \"get topics\", updateTopics: \"update topics\", listRuns: \"list runs\", getRun: \"get run\", listRunSteps: \"list run steps\", getRunStep: \"get run step\" }; const resource = $parameter[\"resource\"]; const operation = $parameter[\"operation\"]; const resourceLabel = resourceLabels[resource] ?? resource; const operationLabel = operationLabels[operation] ?? operation; return operationLabel + \": \" + resourceLabel; })() }}",
37
+ subtitle: "={{(() => { const resourceLabels = { account: \"account\", broadcasts: \"broadcast\", contacts: \"contact\", contactProperties: \"contact property\", domains: \"domain\", email: \"email\", logs: \"log\", receivingEmails: \"received email\", workflows: \"workflow\", events: \"event\", segments: \"segment\", suppressions: \"suppression\", templates: \"template\", topics: \"topic\", webhooks: \"webhook\" }; const operationLabels = { retrieve: \"get\", sendBatch: \"send batch\", listAttachments: \"list attachments\", getAttachment: \"get attachment\", addToSegment: \"add to segment\", listSegments: \"list segments\", removeFromSegment: \"remove from segment\", getTopics: \"get topics\", updateTopics: \"update topics\", listRuns: \"list runs\", getRun: \"get run\", listRunSteps: \"list run steps\", getRunStep: \"get run step\", batchAdd: \"batch add\", batchRemove: \"batch remove\" }; const resource = $parameter[\"resource\"]; const operation = $parameter[\"operation\"]; const resourceLabel = resourceLabels[resource] ?? resource; const operationLabel = operationLabels[operation] ?? operation; return operationLabel + \": \" + resourceLabel; })() }}",
37
38
  defaults: { name: "Resend" },
38
39
  credentials: [{
39
40
  name: "resendOAuth2Api",
@@ -54,13 +55,13 @@ var Resend = class {
54
55
  name: "authentication",
55
56
  type: "options",
56
57
  options: [{
57
- name: "OAuth2 (Recommended)",
58
- value: "oAuth2",
59
- description: "Sign in with your Resend account — n8n registers itself as an OAuth client automatically, no API key needed"
60
- }, {
61
58
  name: "API Key",
62
59
  value: "apiKey",
63
60
  description: "Manually paste a Resend API key"
61
+ }, {
62
+ name: "OAuth2 (Recommended)",
63
+ value: "oAuth2",
64
+ description: "Sign in with your Resend account — n8n registers itself as an OAuth client automatically, no API key needed"
64
65
  }],
65
66
  default: "oAuth2"
66
67
  },
@@ -120,6 +121,11 @@ var Resend = class {
120
121
  value: "segments",
121
122
  description: "Create, update, delete, or list contact segments for grouping contacts based on criteria"
122
123
  },
124
+ {
125
+ name: "Suppression",
126
+ value: "suppressions",
127
+ description: "Add, remove, or list suppressed email addresses that Resend skips at send time to avoid hard bounces and spam complaints"
128
+ },
123
129
  {
124
130
  name: "Template",
125
131
  value: "templates",
@@ -149,6 +155,7 @@ var Resend = class {
149
155
  ...require_nodes_Resend_actions_domain_index.descriptions,
150
156
  ...require_nodes_Resend_actions_broadcast_index.descriptions,
151
157
  ...require_nodes_Resend_actions_segment_index.descriptions,
158
+ ...require_nodes_Resend_actions_suppression_index.descriptions,
152
159
  ...require_nodes_Resend_actions_topic_index.descriptions,
153
160
  ...require_nodes_Resend_actions_contact_index.descriptions,
154
161
  ...require_nodes_Resend_actions_contactProperty_index.descriptions,
@@ -168,6 +175,7 @@ var Resend = class {
168
175
  getEmails: require_nodes_Resend_methods_index.getEmails,
169
176
  getReceivedEmails: require_nodes_Resend_methods_index.getReceivedEmails,
170
177
  getSegments: require_nodes_Resend_methods_index.getSegments,
178
+ getSuppressions: require_nodes_Resend_methods_index.getSuppressions,
171
179
  getTemplateVariables: require_nodes_Resend_methods_index.getTemplateVariables,
172
180
  getTemplates: require_nodes_Resend_methods_index.getTemplates,
173
181
  getTopics: require_nodes_Resend_methods_index.getTopics,
@@ -181,6 +189,7 @@ var Resend = class {
181
189
  getEmails: require_nodes_Resend_methods_index.getEmailsListSearch,
182
190
  getReceivedEmails: require_nodes_Resend_methods_index.getReceivedEmailsListSearch,
183
191
  getSegments: require_nodes_Resend_methods_index.getSegmentsListSearch,
192
+ getSuppressions: require_nodes_Resend_methods_index.getSuppressionsListSearch,
184
193
  getTemplates: require_nodes_Resend_methods_index.getTemplatesListSearch,
185
194
  getTemplateVariables: require_nodes_Resend_methods_index.getTemplateVariablesListSearch,
186
195
  getTopics: require_nodes_Resend_methods_index.getTopicsListSearch,
@@ -1,7 +1,19 @@
1
- import { INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from "n8n-workflow";
1
+ import { ICredentialTestFunctions, ICredentialsDecrypted, IHookFunctions, INodeCredentialTestResult, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from "n8n-workflow";
2
2
  //#region nodes/Resend/ResendTrigger.node.d.ts
3
3
  declare class ResendTrigger implements INodeType {
4
4
  description: INodeTypeDescription;
5
+ methods: {
6
+ credentialTest: {
7
+ resendWebhookSigningSecretTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult>;
8
+ };
9
+ };
10
+ webhookMethods: {
11
+ default: {
12
+ checkExists(this: IHookFunctions): Promise<boolean>;
13
+ create(this: IHookFunctions): Promise<boolean>;
14
+ delete(this: IHookFunctions): Promise<boolean>;
15
+ };
16
+ };
5
17
  webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
6
18
  }
7
19
  //#endregion
@@ -32,6 +32,31 @@ async function verifySvixSignature(payload, svixId, svixTimestamp, svixSignature
32
32
  }
33
33
  throw new n8n_workflow.NodeOperationError(node, "Invalid webhook signature");
34
34
  }
35
+ async function resendApiRequest(method, endpoint, body) {
36
+ return await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
37
+ url: `https://api.resend.com${endpoint}`,
38
+ method,
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ "User-Agent": "n8n-nodes-resend"
42
+ },
43
+ json: true,
44
+ ...body ? { body } : {}
45
+ });
46
+ }
47
+ function isNotFoundError(error) {
48
+ var _ref, _e$httpCode, _e$response;
49
+ const e = error;
50
+ const code = (_ref = (_e$httpCode = e === null || e === void 0 ? void 0 : e.httpCode) !== null && _e$httpCode !== void 0 ? _e$httpCode : e === null || e === void 0 ? void 0 : e.statusCode) !== null && _ref !== void 0 ? _ref : e === null || e === void 0 || (_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.status;
51
+ return String(code) === "404";
52
+ }
53
+ async function hasResendApiCredential(context) {
54
+ try {
55
+ return Boolean(await context.getCredentials("resendApi"));
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
35
60
  var ResendTrigger = class {
36
61
  constructor() {
37
62
  this.description = {
@@ -48,10 +73,14 @@ var ResendTrigger = class {
48
73
  defaults: { name: "Resend Trigger" },
49
74
  credentials: [{
50
75
  name: "resendWebhookSigningSecretApi",
51
- required: true
76
+ required: false,
77
+ testedBy: "resendWebhookSigningSecretTest"
78
+ }, {
79
+ name: "resendApi",
80
+ required: false
52
81
  }],
53
82
  triggerPanel: {
54
- header: "Copy the webhook URL below and paste it into your Resend dashboard webhook configuration.",
83
+ header: "Add a Resend API credential to register this webhook automatically, or copy the webhook URL below and paste it into your Resend dashboard webhook configuration.",
55
84
  executionsHelp: {
56
85
  inactive: "Webhooks have two modes: test and production.<br><br><b>Use test mode while you build your workflow</b>. Click the \"Listen for test event\" button, then paste the test URL into your Resend webhook configuration. The webhook executions will show up in the editor.<br><br><b>Use production mode to run your workflow automatically</b>. Activate the workflow, then paste the production URL into your Resend webhook configuration. These executions will show up in the executions list, but not in the editor.",
57
86
  active: "Webhooks have two modes: test and production.<br><br><b>Use test mode while you build your workflow</b>. Click the \"Listen for test event\" button, then paste the test URL into your Resend webhook configuration. The webhook executions will show up in the editor.<br><br><b>Use production mode to run your workflow automatically</b>. Since the workflow is activated, you can paste the production URL into your Resend webhook configuration. These executions will show up in the executions list, but not in the editor."
@@ -152,16 +181,92 @@ var ResendTrigger = class {
152
181
  }
153
182
  ],
154
183
  description: "Select the Resend event types to listen for"
155
- }]
184
+ }],
185
+ usableAsTool: true
156
186
  };
187
+ this.methods = { credentialTest: { async resendWebhookSigningSecretTest(credential) {
188
+ var _credential$data;
189
+ const secret = typeof ((_credential$data = credential.data) === null || _credential$data === void 0 ? void 0 : _credential$data.webhookSigningSecret) === "string" ? credential.data.webhookSigningSecret.trim() : "";
190
+ if (!secret.startsWith("whsec_")) return {
191
+ status: "Error",
192
+ message: "Signing secret must start with \"whsec_\". Copy it from the webhook settings page in your Resend dashboard."
193
+ };
194
+ const encoded = secret.slice(6);
195
+ if (!encoded || Buffer.from(encoded, "base64").length === 0) return {
196
+ status: "Error",
197
+ message: "Signing secret is not valid base64"
198
+ };
199
+ return {
200
+ status: "OK",
201
+ message: "Signing secret format is valid"
202
+ };
203
+ } } };
204
+ this.webhookMethods = { default: {
205
+ async checkExists() {
206
+ if (!await hasResendApiCredential(this)) return true;
207
+ const webhookData = this.getWorkflowStaticData("node");
208
+ if (!webhookData.webhookId) return false;
209
+ try {
210
+ await resendApiRequest.call(this, "GET", `/webhooks/${webhookData.webhookId}`);
211
+ return true;
212
+ } catch (error) {
213
+ if (isNotFoundError(error)) {
214
+ delete webhookData.webhookId;
215
+ delete webhookData.webhookSigningSecret;
216
+ return false;
217
+ }
218
+ throw new n8n_workflow.NodeApiError(this.getNode(), error);
219
+ }
220
+ },
221
+ async create() {
222
+ var _ref2, _response$data, _ref3, _response$data2;
223
+ if (!await hasResendApiCredential(this)) return true;
224
+ const webhookUrl = this.getNodeWebhookUrl("default");
225
+ const events = this.getNodeParameter("events");
226
+ const response = await resendApiRequest.call(this, "POST", "/webhooks", {
227
+ endpoint: webhookUrl,
228
+ events
229
+ });
230
+ const webhookId = (_ref2 = response.id) !== null && _ref2 !== void 0 ? _ref2 : (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.id;
231
+ if (!webhookId) throw new n8n_workflow.NodeOperationError(this.getNode(), "Resend did not return a webhook ID when creating the webhook");
232
+ const signingSecret = (_ref3 = response.signing_secret) !== null && _ref3 !== void 0 ? _ref3 : (_response$data2 = response.data) === null || _response$data2 === void 0 ? void 0 : _response$data2.signing_secret;
233
+ const webhookData = this.getWorkflowStaticData("node");
234
+ webhookData.webhookId = webhookId;
235
+ if (signingSecret) webhookData.webhookSigningSecret = signingSecret;
236
+ return true;
237
+ },
238
+ async delete() {
239
+ const webhookData = this.getWorkflowStaticData("node");
240
+ if (!webhookData.webhookId) return true;
241
+ if (await hasResendApiCredential(this)) try {
242
+ await resendApiRequest.call(this, "DELETE", `/webhooks/${webhookData.webhookId}`);
243
+ } catch (error) {
244
+ if (!isNotFoundError(error)) throw new n8n_workflow.NodeApiError(this.getNode(), error);
245
+ }
246
+ delete webhookData.webhookId;
247
+ delete webhookData.webhookSigningSecret;
248
+ return true;
249
+ }
250
+ } };
157
251
  }
158
252
  async webhook() {
159
253
  const bodyData = this.getBodyData();
160
254
  const headers = this.getHeaderData();
161
255
  const request = this.getRequestObject();
162
256
  const subscribedEvents = this.getNodeParameter("events");
163
- const webhookSigningSecret = (await this.getCredentials("resendWebhookSigningSecretApi")).webhookSigningSecret;
164
- if (webhookSigningSecret && webhookSigningSecret.trim() !== "") try {
257
+ const webhookData = this.getWorkflowStaticData("node");
258
+ let webhookSigningSecret = typeof webhookData.webhookSigningSecret === "string" ? webhookData.webhookSigningSecret : "";
259
+ if (!webhookSigningSecret) try {
260
+ var _ref4;
261
+ webhookSigningSecret = (_ref4 = (await this.getCredentials("resendWebhookSigningSecretApi")).webhookSigningSecret) !== null && _ref4 !== void 0 ? _ref4 : "";
262
+ } catch {
263
+ webhookSigningSecret = "";
264
+ }
265
+ if (!webhookSigningSecret || webhookSigningSecret.trim() === "") {
266
+ this.getResponseObject().status(401).json({ error: "Webhook signing secret is not configured" });
267
+ return { noWebhookResponse: true };
268
+ }
269
+ try {
165
270
  var _rawBody;
166
271
  const rawBody = (_rawBody = request.rawBody) !== null && _rawBody !== void 0 ? _rawBody : request.body;
167
272
  const payload = typeof rawBody === "string" ? rawBody : Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : JSON.stringify(bodyData !== null && bodyData !== void 0 ? bodyData : {});
@@ -173,7 +278,7 @@ var ResendTrigger = class {
173
278
  return { noWebhookResponse: true };
174
279
  }
175
280
  await verifySvixSignature(payload, svixId, svixTimestamp, svixSignature, webhookSigningSecret, this.getNode());
176
- } catch (_error) {
281
+ } catch {
177
282
  this.getResponseObject().status(401).json({ error: "Invalid webhook signature" });
178
283
  return { noWebhookResponse: true };
179
284
  }
@@ -19,7 +19,7 @@ const operations = [{
19
19
  name: "Disconnect",
20
20
  value: "disconnect",
21
21
  description: "Revoke the connected Resend OAuth2 grant, ending the connection to your Resend account",
22
- action: "Disconnect the Resend account"
22
+ action: "Disconnect the resend account"
23
23
  }],
24
24
  default: "disconnect"
25
25
  }];
@@ -20,10 +20,10 @@ const description = [require_nodes_Resend_utils_dynamicFields.createDynamicIdFie
20
20
  } }
21
21
  })];
22
22
  async function execute(index) {
23
- var _data;
23
+ var _ref;
24
24
  const domainId = require_nodes_Resend_utils_dynamicFields.resolveDynamicIdValue(this, "domainId", index);
25
25
  const response = await require_nodes_Resend_transport_index.apiRequest.call(this, "GET", `/domains/${encodeURIComponent(domainId)}/tracking-domains`);
26
- const executionData = ((_data = response === null || response === void 0 ? void 0 : response.data) !== null && _data !== void 0 ? _data : []).map((item, _i) => ({
26
+ const executionData = ((_ref = response.data) !== null && _ref !== void 0 ? _ref : []).map((item) => ({
27
27
  json: item,
28
28
  pairedItem: { item: index }
29
29
  }));
@@ -461,7 +461,7 @@ async function execute(index) {
461
461
  if (additionalOptions.idempotencyKey) requestHeaders["Idempotency-Key"] = additionalOptions.idempotencyKey;
462
462
  let response;
463
463
  try {
464
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
464
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
465
465
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails`,
466
466
  method: "POST",
467
467
  headers: requestHeaders,
@@ -3,6 +3,6 @@ declare namespace sendAndWait_operation_d_exports {
3
3
  export { SEND_AND_WAIT_OPERATION, description, execute };
4
4
  }
5
5
  declare const description: INodeProperties[];
6
- declare function execute(this: IExecuteFunctions, _index: number): Promise<INodeExecutionData[]>;
6
+ declare function execute(this: IExecuteFunctions): Promise<INodeExecutionData[]>;
7
7
  //#endregion
8
8
  export { SEND_AND_WAIT_OPERATION, description, execute, sendAndWait_operation_d_exports };
@@ -29,7 +29,7 @@ const description = require_nodes_Resend_utils_sendAndWait_utils.getSendAndWaitP
29
29
  defaultApproveLabel: "Approve",
30
30
  defaultDisapproveLabel: "Decline"
31
31
  });
32
- async function execute(_index) {
32
+ async function execute() {
33
33
  const email = require_nodes_Resend_utils_sendAndWait_utils.createEmail(this);
34
34
  await require_nodes_Resend_utils_sendAndWait_utils.sendResendEmail(this, email);
35
35
  const waitTill = require_nodes_Resend_utils_sendAndWait_utils.configureWaitTillDate(this);
@@ -48,7 +48,8 @@ const description = [{
48
48
  displayName: "Headers",
49
49
  name: "headers",
50
50
  type: "fixedCollection",
51
- default: {},
51
+ default: { headers: [] },
52
+ typeOptions: { multipleValues: true },
52
53
  options: [{
53
54
  name: "headers",
54
55
  displayName: "Header",
@@ -74,11 +75,20 @@ const description = [{
74
75
  default: "",
75
76
  description: "Email address where replies should be sent. Can be different from the sender address."
76
77
  },
78
+ {
79
+ displayName: "Scheduled At",
80
+ name: "scheduledAt",
81
+ type: "string",
82
+ default: "",
83
+ placeholder: "in 1 hour",
84
+ description: "Schedule this email to be sent at a future time. Accepts natural language like \"in 1 hour\" or ISO 8601 format \"2024-12-25T09:00:00Z\". Each email in the batch can be scheduled independently."
85
+ },
77
86
  {
78
87
  displayName: "Tags",
79
88
  name: "tags",
80
89
  type: "fixedCollection",
81
- default: {},
90
+ default: { tags: [] },
91
+ typeOptions: { multipleValues: true },
82
92
  options: [{
83
93
  name: "tags",
84
94
  displayName: "Tag",
@@ -170,7 +180,8 @@ const description = [{
170
180
  displayName: "Template Variables",
171
181
  name: "templateVariables",
172
182
  type: "fixedCollection",
173
- default: {},
183
+ default: { variables: [] },
184
+ typeOptions: { multipleValues: true },
174
185
  description: "Key-value pairs to replace template placeholders. Keys must match the template variable names.",
175
186
  options: [{
176
187
  name: "variables",
@@ -298,6 +309,8 @@ async function execute(index) {
298
309
  });
299
310
  const topicId = additionalOptions.topicId;
300
311
  if (topicId) emailObj.topic_id = topicId;
312
+ const scheduledAt = additionalOptions.scheduledAt;
313
+ if (scheduledAt) emailObj.scheduled_at = scheduledAt;
301
314
  if (contentType === "template") {
302
315
  if (!email.templateId) throw new n8n_workflow.NodeOperationError(this.getNode(), "Template Name or ID is required for batch emails when using templates.", { itemIndex: index });
303
316
  if (email.html || email.text) throw new n8n_workflow.NodeOperationError(this.getNode(), "HTML/Text Content cannot be used when sending batch emails with templates.", { itemIndex: index });
@@ -322,7 +335,7 @@ async function execute(index) {
322
335
  if (batchOptions.idempotency_key) headers["Idempotency-Key"] = batchOptions.idempotency_key;
323
336
  let response;
324
337
  try {
325
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
338
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
326
339
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails/batch`,
327
340
  method: "POST",
328
341
  headers,
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_nodes_Resend_transport_index = require("../transport/index.js");
2
3
  const require_nodes_Resend_actions_account_index = require("./account/index.js");
3
4
  const require_nodes_Resend_actions_broadcast_index = require("./broadcast/index.js");
4
5
  const require_nodes_Resend_actions_contact_index = require("./contact/index.js");
@@ -9,6 +10,7 @@ const require_nodes_Resend_actions_event_index = require("./event/index.js");
9
10
  const require_nodes_Resend_actions_log_index = require("./log/index.js");
10
11
  const require_nodes_Resend_actions_receivingEmail_index = require("./receivingEmail/index.js");
11
12
  const require_nodes_Resend_actions_segment_index = require("./segment/index.js");
13
+ const require_nodes_Resend_actions_suppression_index = require("./suppression/index.js");
12
14
  const require_nodes_Resend_actions_template_index = require("./template/index.js");
13
15
  const require_nodes_Resend_actions_topic_index = require("./topic/index.js");
14
16
  const require_nodes_Resend_actions_webhook_index = require("./webhook/index.js");
@@ -22,6 +24,7 @@ const resourceModules = {
22
24
  domains: require_nodes_Resend_actions_domain_index.domain_exports,
23
25
  broadcasts: require_nodes_Resend_actions_broadcast_index.broadcast_exports,
24
26
  segments: require_nodes_Resend_actions_segment_index.segment_exports,
27
+ suppressions: require_nodes_Resend_actions_suppression_index.suppression_exports,
25
28
  topics: require_nodes_Resend_actions_topic_index.topic_exports,
26
29
  contacts: require_nodes_Resend_actions_contact_index.contact_exports,
27
30
  contactProperties: require_nodes_Resend_actions_contactProperty_index.contactProperty_exports,
@@ -54,7 +57,7 @@ async function router() {
54
57
  });
55
58
  continue;
56
59
  }
57
- throw error;
60
+ require_nodes_Resend_transport_index.handleResendApiError(this.getNode(), error, i);
58
61
  }
59
62
  return [returnData];
60
63
  }
@@ -0,0 +1,8 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeProperties } from "n8n-workflow";
2
+ declare namespace batchAdd_operation_d_exports {
3
+ export { description, execute };
4
+ }
5
+ declare const description: INodeProperties[];
6
+ declare function execute(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]>;
7
+ //#endregion
8
+ export { batchAdd_operation_d_exports, description, execute };
@@ -0,0 +1,41 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../../../../_virtual/_rolldown/runtime.js");
3
+ const require_nodes_Resend_transport_index = require("../../transport/index.js");
4
+ let n8n_workflow = require("n8n-workflow");
5
+ //#region nodes/Resend/actions/suppression/batchAdd.operation.ts
6
+ var batchAdd_operation_exports = /* @__PURE__ */ require_runtime.__exportAll({
7
+ description: () => description,
8
+ execute: () => execute
9
+ });
10
+ const description = [{
11
+ displayName: "Emails",
12
+ name: "suppressionEmails",
13
+ type: "string",
14
+ required: true,
15
+ default: "",
16
+ placeholder: "one@example.com, two@example.com",
17
+ displayOptions: { show: {
18
+ resource: ["suppressions"],
19
+ operation: ["batchAdd"]
20
+ } },
21
+ description: "Comma-separated list of email addresses to add to the suppression list. Up to 100 addresses per request."
22
+ }];
23
+ async function execute(index) {
24
+ const emails = require_nodes_Resend_transport_index.normalizeEmailList(this.getNodeParameter("suppressionEmails", index));
25
+ if (emails.length === 0) throw new n8n_workflow.NodeOperationError(this.getNode(), "Provide at least one email address to suppress", { itemIndex: index });
26
+ if (emails.length > 100) throw new n8n_workflow.NodeOperationError(this.getNode(), "A batch add supports at most 100 email addresses per request", { itemIndex: index });
27
+ const body = { emails };
28
+ return [{
29
+ json: await require_nodes_Resend_transport_index.apiRequest.call(this, "POST", "/suppressions/batch/add", body),
30
+ pairedItem: { item: index }
31
+ }];
32
+ }
33
+ //#endregion
34
+ Object.defineProperty(exports, "batchAdd_operation_exports", {
35
+ enumerable: true,
36
+ get: function() {
37
+ return batchAdd_operation_exports;
38
+ }
39
+ });
40
+ exports.description = description;
41
+ exports.execute = execute;
@@ -0,0 +1,8 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeProperties } from "n8n-workflow";
2
+ declare namespace batchRemove_operation_d_exports {
3
+ export { description, execute };
4
+ }
5
+ declare const description: INodeProperties[];
6
+ declare function execute(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]>;
7
+ //#endregion
8
+ export { batchRemove_operation_d_exports, description, execute };
@@ -0,0 +1,80 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../../../../_virtual/_rolldown/runtime.js");
3
+ const require_nodes_Resend_transport_index = require("../../transport/index.js");
4
+ let n8n_workflow = require("n8n-workflow");
5
+ //#region nodes/Resend/actions/suppression/batchRemove.operation.ts
6
+ var batchRemove_operation_exports = /* @__PURE__ */ require_runtime.__exportAll({
7
+ description: () => description,
8
+ execute: () => execute
9
+ });
10
+ const description = [
11
+ {
12
+ displayName: "Remove By",
13
+ name: "suppressionRemoveBy",
14
+ type: "options",
15
+ default: "emails",
16
+ displayOptions: { show: {
17
+ resource: ["suppressions"],
18
+ operation: ["batchRemove"]
19
+ } },
20
+ options: [{
21
+ name: "Emails",
22
+ value: "emails",
23
+ description: "Remove suppressions matching these email addresses"
24
+ }, {
25
+ name: "IDs",
26
+ value: "ids",
27
+ description: "Remove suppressions matching these suppression IDs"
28
+ }],
29
+ description: "Whether to remove suppressions by email address or by suppression ID. Provide one or the other, not both."
30
+ },
31
+ {
32
+ displayName: "Emails",
33
+ name: "suppressionEmails",
34
+ type: "string",
35
+ required: true,
36
+ default: "",
37
+ placeholder: "one@example.com, two@example.com",
38
+ displayOptions: { show: {
39
+ resource: ["suppressions"],
40
+ operation: ["batchRemove"],
41
+ suppressionRemoveBy: ["emails"]
42
+ } },
43
+ description: "Comma-separated list of email addresses to remove from the suppression list. Up to 100 addresses per request."
44
+ },
45
+ {
46
+ displayName: "IDs",
47
+ name: "suppressionIds",
48
+ type: "string",
49
+ required: true,
50
+ default: "",
51
+ placeholder: "e169aa45-1ecf-4183-9955-b1499d5701d3, ...",
52
+ displayOptions: { show: {
53
+ resource: ["suppressions"],
54
+ operation: ["batchRemove"],
55
+ suppressionRemoveBy: ["ids"]
56
+ } },
57
+ description: "Comma-separated list of suppression IDs to remove from the suppression list. Up to 100 IDs per request."
58
+ }
59
+ ];
60
+ async function execute(index) {
61
+ const removeBy = this.getNodeParameter("suppressionRemoveBy", index, "emails");
62
+ const field = removeBy === "ids" ? "suppressionIds" : "suppressionEmails";
63
+ const values = require_nodes_Resend_transport_index.normalizeEmailList(this.getNodeParameter(field, index));
64
+ if (values.length === 0) throw new n8n_workflow.NodeOperationError(this.getNode(), `Provide at least one ${removeBy === "ids" ? "suppression ID" : "email address"} to remove`, { itemIndex: index });
65
+ if (values.length > 100) throw new n8n_workflow.NodeOperationError(this.getNode(), "A batch remove supports at most 100 entries per request", { itemIndex: index });
66
+ const body = { [removeBy]: values };
67
+ return [{
68
+ json: await require_nodes_Resend_transport_index.apiRequest.call(this, "POST", "/suppressions/batch/remove", body),
69
+ pairedItem: { item: index }
70
+ }];
71
+ }
72
+ //#endregion
73
+ Object.defineProperty(exports, "batchRemove_operation_exports", {
74
+ enumerable: true,
75
+ get: function() {
76
+ return batchRemove_operation_exports;
77
+ }
78
+ });
79
+ exports.description = description;
80
+ exports.execute = execute;
@@ -0,0 +1,8 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeProperties } from "n8n-workflow";
2
+ declare namespace create_operation_d_exports {
3
+ export { description, execute };
4
+ }
5
+ declare const description: INodeProperties[];
6
+ declare function execute(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]>;
7
+ //#endregion
8
+ export { create_operation_d_exports, description, execute };