{ "kind": "open-flow-workflow", "version": 1, "name": "Send a Sample Email to Two Recipients", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_fa10ecb257137c44": { "name": "Enter recipients", "kind": "start", "inputDefs": [ { "jsonSchema": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "nullable": false, "handle": "recipients" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "from" } ] }, "n_49d139750782412e": { "inputs": { "to": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fa10ecb257137c44", "output": "recipients" } ] }, "from": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fa10ecb257137c44", "output": "from" } ] }, "subject": { "kind": "value", "value": "n8n Rocks" }, "message": { "kind": "value", "value": "This is a sample message body in an email\n" }, "region": { "kind": "value", "value": "us-east-1" }, "accessKeyId": { "kind": "unset" }, "secretAccessKey": { "kind": "unset" }, "sessionToken": { "kind": "value", "value": null } }, "name": "Sign SES request", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "nullable": false, "handle": "to" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "from" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "subject" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "message" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "region" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "accessKeyId" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "secretAccessKey" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "sessionToken" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "authorization" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "amzDate" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "body" } ], "name": "Sign SES request", "moduleId": "n_9406b9302a081a73", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_9677024eafa6d56a": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_49d139750782412e", "output": "url" } ] }, "header.Content-Type": { "kind": "value", "value": "application/json" }, "header.Authorization": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_49d139750782412e", "output": "authorization" } ] }, "header.X-Amz-Date": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_49d139750782412e", "output": "amzDate" } ] }, "header.X-Amz-Security-Token": { "kind": "value", "value": null }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_49d139750782412e", "output": "body" } ] } }, "name": "Send with Amazon SES", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.Content-Type" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.Authorization" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.X-Amz-Date" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.X-Amz-Security-Token" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "body" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Send with Amazon SES", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [ "Content-Type", "Authorization", "X-Amz-Date", "X-Amz-Security-Token" ] }, "bodyFormat": "text", "authentication": { "type": "none" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_541570beb53176a2": { "name": "SES response", "kind": "outputs", "outputDefs": [ { "jsonSchema": {}, "nullable": true, "handle": "response" } ], "outputMappings": { "response": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9677024eafa6d56a", "output": "body" } ] } } } }, "edges": [ { "source": "n_fa10ecb257137c44", "target": "n_49d139750782412e" }, { "source": "n_49d139750782412e", "target": "n_9677024eafa6d56a" }, { "source": "n_9677024eafa6d56a", "target": "n_541570beb53176a2" } ] } }, "modules": { "n_9406b9302a081a73": { "name": "Sign SES request", "imports": [], "source": "import{createHash,createHmac}from'node:crypto';\nexport default function sign({to,from,subject,message,region,accessKeyId,secretAccessKey,sessionToken}){for(const [name,v]of Object.entries({from,region,accessKeyId,secretAccessKey}))if(typeof v!=='string'||!v)throw Error('Configure '+name);if(!/^[a-z]{2}(?:-[a-z]+){1,2}-[0-9]+$/.test(region))throw Error('Invalid AWS region');const host='email.'+region+'.amazonaws.com'+(region.startsWith('cn-')?'.cn':''),path='/v2/email/outbound-emails',body=JSON.stringify({FromEmailAddress:from,Destination:{ToAddresses:to},Content:{Simple:{Subject:{Data:subject,Charset:'UTF-8'},Body:{Text:{Data:message,Charset:'UTF-8'}}}}}),timestamp=new Date().toISOString().replace(/[:-]|\\.\\d{3}/g,''),date=timestamp.slice(0,8),headers={'content-type':'application/json',host,'x-amz-date':timestamp,...(sessionToken?{'x-amz-security-token':sessionToken}:{})},names=Object.keys(headers).sort(),signedHeaders=names.join(';'),canonicalHeaders=names.map(k=>k+':'+headers[k].trim().replace(/\\s+/g,' ')+'\\n').join(''),hash=x=>createHash('sha256').update(x).digest('hex'),hmac=(k,v)=>createHmac('sha256',k).update(v).digest(),scope=date+'/'+region+'/ses/aws4_request',canonical=['POST',path,'',canonicalHeaders,signedHeaders,hash(body)].join('\\n'),toSign=['AWS4-HMAC-SHA256',timestamp,scope,hash(canonical)].join('\\n'),key=hmac(hmac(hmac(hmac('AWS4'+secretAccessKey,date),region),'ses'),'aws4_request'),sig=createHmac('sha256',key).update(toSign).digest('hex');delete headers.host;headers.authorization='AWS4-HMAC-SHA256 Credential='+accessKeyId+'/'+scope+', SignedHeaders='+signedHeaders+', Signature='+sig;return{url:'https://'+host+path,authorization:headers.authorization,amzDate:timestamp,body}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }