diff --git a/packages/nodes-base/nodes/SendGrid/MailDescription.ts b/packages/nodes-base/nodes/SendGrid/MailDescription.ts index 067c52597c..11459e1c43 100644 --- a/packages/nodes-base/nodes/SendGrid/MailDescription.ts +++ b/packages/nodes-base/nodes/SendGrid/MailDescription.ts @@ -251,6 +251,15 @@ export const mailFields: INodeProperties[] = [ default: '', description: 'The IP Pool that you would like to send this email from', }, + { + displayName: 'Reply-To Email', + name: 'replyToEmail', + type: 'string', + default: '', + placeholder: 'reply@domain.com', + description: + 'Comma-separated list of email addresses that will appear in the reply-to field of the email', + }, { displayName: 'Headers', name: 'headers', @@ -306,6 +315,7 @@ export type SendMailBody = { }>; ip_pool_name?: string; from: EmailName; + reply_to_list?: EmailName[]; template_id?: string; content?: Array<{ type: string; diff --git a/packages/nodes-base/nodes/SendGrid/SendGrid.node.ts b/packages/nodes-base/nodes/SendGrid/SendGrid.node.ts index 6e1379f5fa..0658ca666f 100644 --- a/packages/nodes-base/nodes/SendGrid/SendGrid.node.ts +++ b/packages/nodes-base/nodes/SendGrid/SendGrid.node.ts @@ -524,6 +524,7 @@ export class SendGrid implements INodeType { attachments, categories, ipPoolName, + replyToEmail, } = this.getNodeParameter('additionalFields', i) as { bccEmail: string; ccEmail: string; @@ -533,6 +534,7 @@ export class SendGrid implements INodeType { attachments: string; categories: string; ipPoolName: string; + replyToEmail: string; }; const body: SendMailBody = { @@ -630,6 +632,12 @@ export class SendGrid implements INodeType { body.personalizations[0].send_at = moment.tz(sendAt, timezone).unix(); } + if (replyToEmail) { + body.reply_to_list = replyToEmail + .split(',') + .map((entry) => ({ email: entry.trim() })); + } + const data = await sendGridApiRequest.call(this, '/mail/send', 'POST', body, qs, { resolveWithFullResponse: true, }); diff --git a/packages/nodes-base/nodes/SendGrid/test/SendGrid.node.test.ts b/packages/nodes-base/nodes/SendGrid/test/SendGrid.node.test.ts new file mode 100644 index 0000000000..bfb39136a8 --- /dev/null +++ b/packages/nodes-base/nodes/SendGrid/test/SendGrid.node.test.ts @@ -0,0 +1,30 @@ +/* eslint-disable n8n-nodes-base/node-param-display-name-miscased */ +import nock from 'nock'; + +import { testWorkflows } from '@test/nodes/Helpers'; + +describe('Test SendGrid Node', () => { + beforeAll(() => { + nock.disableNetConnect(); + }); + + describe('Mail', () => { + const sendgridNock = nock('https://api.sendgrid.com/v3'); + + beforeAll(() => { + sendgridNock + .post( + '/mail/send', + (body: { reply_to_list?: [{ email: string }] }) => + body?.reply_to_list?.[0]?.email === 'test-reply-to@n8n.io', + ) + .reply(202); + }); + + testWorkflows(['nodes/SendGrid/test/mail.workflow.json']); + + it('should make the correct network calls', () => { + sendgridNock.done(); + }); + }); +}); diff --git a/packages/nodes-base/nodes/SendGrid/test/mail.workflow.json b/packages/nodes-base/nodes/SendGrid/test/mail.workflow.json new file mode 100644 index 0000000000..47c231150f --- /dev/null +++ b/packages/nodes-base/nodes/SendGrid/test/mail.workflow.json @@ -0,0 +1,62 @@ +{ + "name": "mail", + "nodes": [ + { + "parameters": {}, + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [0, 0], + "id": "0b4c0843-6007-4687-8e91-cf3b97cb0734", + "name": "When clicking ‘Test workflow’" + }, + { + "parameters": { + "resource": "mail", + "fromEmail": "test@n8n.io", + "fromName": "Test Sender", + "toEmail": "test@n8n.io", + "subject": "Test Subject", + "contentValue": "Test Message", + "additionalFields": { + "replyToEmail": "test-reply-to@n8n.io" + } + }, + "type": "n8n-nodes-base.sendGrid", + "typeVersion": 1, + "position": [220, 0], + "id": "69ea4501-a90d-4067-b9f7-a7b7f2b79a96", + "name": "SendGrid", + "credentials": { + "sendGridApi": { + "id": "3D7B6nvmzW0SZkjG", + "name": "SendGrid account" + } + } + } + ], + "pinData": {}, + "connections": { + "When clicking ‘Test workflow’": { + "main": [ + [ + { + "node": "SendGrid", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "versionId": "7e4ed87a-64b8-4248-b78f-e2db21f1f603", + "meta": { + "templateCredsSetupCompleted": true, + "instanceId": "35e7acdc2e5caa3b0a5fca77da6cc9361ca88ba3e6f6b97ecd8a8cf35cb2ea85" + }, + "id": "YdfKbNlA37FExwxC", + "tags": [] +}