first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,29 @@
{
"node": "n8n-nodes-base.awsSes",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Communication", "Development"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/aws/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awsses/"
}
],
"generic": [
{
"label": "Why business process automation with n8n can change your daily life",
"icon": "🧬",
"url": "https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/"
},
{
"label": "7 no-code workflow automations for Amazon Web Services",
"url": "https://n8n.io/blog/aws-workflow-automation/"
}
]
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,124 @@
import get from 'lodash/get';
import type {
IDataObject,
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IWebhookFunctions,
IHttpRequestOptions,
JsonObject,
IHttpRequestMethods,
} from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';
import { parseString } from 'xml2js';
import { getAwsCredentials } from '../GenericFunctions';
export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: IHttpRequestMethods,
path: string,
body?: string,
headers?: object,
): Promise<any> {
const { credentials, credentialsType } = await getAwsCredentials(this);
const requestOptions = {
qs: {
service,
path,
},
method,
body: JSON.stringify(body),
url: '',
headers,
region: credentials?.region as string,
} as IHttpRequestOptions;
try {
return await this.helpers.requestWithAuthentication.call(this, credentialsType, requestOptions);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject, { parseXml: true });
}
}
export async function awsApiRequestREST(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: IHttpRequestMethods,
path: string,
body?: string,
headers?: object,
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers);
try {
return JSON.parse(response as string);
} catch (error) {
return response;
}
}
export async function awsApiRequestSOAP(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: IHttpRequestMethods,
path: string,
body?: string,
headers?: object,
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers);
try {
return await new Promise((resolve, reject) => {
parseString(response as string, { explicitArray: false }, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
} catch (error) {
return response;
}
}
export async function awsApiRequestSOAPAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
propertyName: string,
service: string,
method: IHttpRequestMethods,
path: string,
body?: string,
query: IDataObject = {},
_headers: IDataObject = {},
_option: IDataObject = {},
_region?: string,
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
const propertyNameArray = propertyName.split('.');
do {
responseData = await awsApiRequestSOAP.call(this, service, method, path, body, query);
if (get(responseData, [propertyNameArray[0], propertyNameArray[1], 'NextToken'])) {
query.NextToken = get(responseData, [
propertyNameArray[0],
propertyNameArray[1],
'NextToken',
]);
}
if (get(responseData, propertyName)) {
if (Array.isArray(get(responseData, propertyName))) {
returnData.push.apply(returnData, get(responseData, propertyName) as IDataObject[]);
} else {
returnData.push(get(responseData, propertyName) as IDataObject);
}
}
} while (
get(responseData, [propertyNameArray[0], propertyNameArray[1], 'NextToken']) !== undefined
);
return returnData;
}
@@ -0,0 +1,35 @@
{
"type": "object",
"properties": {
"SendEmailResponse": {
"type": "object",
"properties": {
"$": {
"type": "object",
"properties": {
"xmlns": {
"type": "string"
}
}
},
"ResponseMetadata": {
"type": "object",
"properties": {
"RequestId": {
"type": "string"
}
}
},
"SendEmailResult": {
"type": "object",
"properties": {
"MessageId": {
"type": "string"
}
}
}
}
}
},
"version": 1
}
@@ -0,0 +1,30 @@
{
"type": "object",
"properties": {
"$": {
"type": "object",
"properties": {
"xmlns": {
"type": "string"
}
}
},
"ResponseMetadata": {
"type": "object",
"properties": {
"RequestId": {
"type": "string"
}
}
},
"SendTemplatedEmailResult": {
"type": "object",
"properties": {
"MessageId": {
"type": "string"
}
}
}
},
"version": 1
}
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 74.375 85"><use xlink:href="#a" x="2.188" y="2.5"/><symbol id="a" overflow="visible"><g stroke="none"><path fill="#876929" d="M16.558 12.75 0 38.591l16.558 25.841 13.227-3.324.654-44.869z"/><path fill="#d9a741" d="m35.049 59.786-18.491 4.645V12.75l18.491 4.645z"/><g fill="#876929"><path d="M32.849 21.614 35.05 80 70 62.867l-.01-43.615-8.914 1.448-28.228.913z"/><path d="m46.184 33.149 10.906-.632 10.778-19.164L40.612 0 30.439 4.364z"/></g><path fill="#d9a741" d="m40.612 0 27.256 13.353L57.09 32.517z"/><path fill="#876929" d="M35.049 5.539 57.09 44.742l3.788 22.595L35.049 80l-10.46-5.131V9.64z"/><path fill="#d9a741" d="M69.991 19.251 70 62.867 35.05 80V5.539l22.041 39.203L69.99 19.251z"/></g></symbol></svg>

After

Width:  |  Height:  |  Size: 903 B

@@ -0,0 +1,174 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import { NodeConnectionTypes, type WorkflowTestData } from 'n8n-workflow';
import assert from 'node:assert';
import qs from 'node:querystring';
import { credentials } from '../../__tests__/credentials';
describe('AwsSes Node', () => {
const testHarness = new NodeTestHarness();
const email = 'test+user@example.com';
const templateData = {
Name: 'Special. Characters @#$%^&*()_-',
};
const tests: WorkflowTestData[] = [
{
description: 'should create customVerificationEmail',
input: {
workflowData: {
nodes: [
{
parameters: {},
id: '61c910d6-9997-4bc0-b95d-2b2771c3110f',
name: 'When clicking Execute workflow',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [720, 380],
},
{
parameters: {
resource: 'customVerificationEmail',
fromEmailAddress: 'test+user@example.com',
templateName: 'testTemplate',
templateContent: 'testContent',
templateSubject: 'testSubject',
successRedirectionURL: 'http://success.url/',
failureRedirectionURL: 'http://failure.url/',
},
id: '5780c7b2-7e7f-44d2-980d-a162d28bf152',
name: 'AWS SES',
type: 'n8n-nodes-base.awsSes',
typeVersion: 1,
position: [940, 380],
credentials: {
aws: {
id: '1',
name: 'AWS',
},
},
},
],
connections: {
'When clicking Execute workflow': {
main: [
[
{
node: 'AWS SES',
type: NodeConnectionTypes.Main,
index: 0,
},
],
],
},
},
},
},
output: {
nodeData: {
'AWS SES': [[{ json: { success: 'true' } }]],
},
},
nock: {
baseUrl: 'https://email.eu-central-1.amazonaws.com',
mocks: [
{
method: 'post',
path: '/',
requestBody: (body: any) => {
assert.deepEqual(qs.parse(body), {
Action: 'CreateCustomVerificationEmailTemplate',
FromEmailAddress: 'test+user@example.com',
SuccessRedirectionURL: 'http://success.url/',
FailureRedirectionURL: 'http://failure.url/',
TemplateName: 'testTemplate',
TemplateSubject: 'testSubject',
TemplateContent: 'testContent',
});
return true;
},
statusCode: 200,
responseBody:
'<CreateCustomVerificationEmailTemplateResponse><success>true</success></CreateCustomVerificationEmailTemplateResponse>',
},
],
},
},
{
description: 'should URIencode params for sending email with template',
input: {
workflowData: {
nodes: [
{
parameters: {},
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [-180, 520],
id: '363e874a-9054-4a64-bc3f-786719dde626',
name: 'When clicking Execute workflow',
},
{
parameters: {
operation: 'sendTemplate',
templateName: '=Template11',
fromEmail: 'test+user@example.com',
toAddresses: ['test+user@example.com'],
templateDataUi: {
templateDataValues: [
{
key: 'Name',
value: '=Special. Characters @#$%^&*()_-',
},
],
},
additionalFields: {},
},
type: 'n8n-nodes-base.awsSes',
typeVersion: 1,
position: [60, 520],
id: '13bbf4ef-8320-45d1-9210-61b62794a108',
name: 'AWS SES',
credentials: {
aws: {
id: 'Nz0QZhzu3MvfK4TQ',
name: 'AWS account',
},
},
},
],
connections: {
'When clicking Execute workflow': {
main: [
[
{
node: 'AWS SES',
type: NodeConnectionTypes.Main,
index: 0,
},
],
],
},
},
},
},
output: {
nodeData: { 'AWS SES': [[{ json: { success: 'true' } }]] },
},
nock: {
baseUrl: 'https://email.eu-central-1.amazonaws.com',
mocks: [
{
method: 'post',
path: `/?Action=SendTemplatedEmail&Template=Template11&Source=${encodeURIComponent(email)}&Destination.ToAddresses.member.1=${encodeURIComponent(email)}&TemplateData=${encodeURIComponent(JSON.stringify(templateData))}`,
statusCode: 200,
responseBody:
'<SendTemplatedEmailResponse><success>true</success></SendTemplatedEmailResponse>',
},
],
},
},
];
for (const testData of tests) {
testHarness.setupTest(testData, { credentials });
}
});