mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
Added Mandrill support
This commit is contained in:
parent
a2b589880f
commit
9d0d85875e
18
packages/nodes-base/credentials/MandrillApi.credentials.ts
Normal file
18
packages/nodes-base/credentials/MandrillApi.credentials.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import {
|
||||||
|
ICredentialType,
|
||||||
|
NodePropertyTypes,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
|
||||||
|
export class MandrillApi implements ICredentialType {
|
||||||
|
name = 'mandrillApi';
|
||||||
|
displayName = 'Mandrill API';
|
||||||
|
properties = [
|
||||||
|
{
|
||||||
|
displayName: 'API Key',
|
||||||
|
name: 'apiKey',
|
||||||
|
type: 'string' as NodePropertyTypes,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
69
packages/nodes-base/nodes/Mandrill/GenericFunctions.ts
Normal file
69
packages/nodes-base/nodes/Mandrill/GenericFunctions.ts
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import { OptionsWithUri } from 'request';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IExecuteFunctions,
|
||||||
|
IHookFunctions,
|
||||||
|
ILoadOptionsFunctions,
|
||||||
|
IExecuteSingleFunctions
|
||||||
|
} from 'n8n-core';
|
||||||
|
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
export async function mandrillApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, resource: string, method: string, action: string, body: any = {}, headers?: object): Promise<any> { // tslint:disable-line:no-any
|
||||||
|
const credentials = this.getCredentials('mandrillApi');
|
||||||
|
|
||||||
|
if (credentials === undefined) {
|
||||||
|
throw new Error('No credentials got returned!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = Object.assign({ }, body, { key: credentials.apiKey })
|
||||||
|
|
||||||
|
const endpoint = 'mandrillapp.com/api/1.0';
|
||||||
|
|
||||||
|
const options: OptionsWithUri = {
|
||||||
|
headers: headers,
|
||||||
|
method,
|
||||||
|
uri: `https://${endpoint}${resource}${action}.json`,
|
||||||
|
body: data,
|
||||||
|
json: true
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await this.helpers.request!(options);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
const errorMessage = error.response.body.message || error.response.body.Message;
|
||||||
|
if (error.name === 'Invalid_Key') {
|
||||||
|
throw new Error('The provided API key is not a valid Mandrill API key');
|
||||||
|
} else if (error.name === 'ValidationError') {
|
||||||
|
throw new Error('The parameters passed to the API call are invalid or not provided when required');
|
||||||
|
} else if (error.name === 'GeneralError') {
|
||||||
|
throw new Error('An unexpected error occurred processing the request. Mandrill developers will be notified.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorMessage !== undefined) {
|
||||||
|
throw errorMessage;
|
||||||
|
}
|
||||||
|
throw error.response.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getToEmailArray(toEmail: String): Array<any> { // tslint:disable-line:no-any
|
||||||
|
let toEmailArray
|
||||||
|
if (toEmail.split(',').length > 0) {
|
||||||
|
const array = toEmail.split(',')
|
||||||
|
toEmailArray = _.map(array, (email) => {
|
||||||
|
return {
|
||||||
|
email: email,
|
||||||
|
type: 'to'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
toEmailArray = [{
|
||||||
|
email: toEmail,
|
||||||
|
type: 'to'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
return toEmailArray
|
||||||
|
}
|
322
packages/nodes-base/nodes/Mandrill/Mandrill.node.ts
Normal file
322
packages/nodes-base/nodes/Mandrill/Mandrill.node.ts
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
import {
|
||||||
|
BINARY_ENCODING,
|
||||||
|
IExecuteSingleFunctions,
|
||||||
|
} from 'n8n-core';
|
||||||
|
import {
|
||||||
|
IDataObject,
|
||||||
|
INodeTypeDescription,
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeType,
|
||||||
|
ILoadOptionsFunctions,
|
||||||
|
INodePropertyOptions,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
import { mandrillApiRequest, getToEmailArray } from './GenericFunctions';
|
||||||
|
|
||||||
|
export class Mandrill implements INodeType {
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://mandrillapp.com/api/docs/messages.JSON.html#method=send-template
|
||||||
|
|
||||||
|
1 - add url strip qs support
|
||||||
|
2 - add subaccount support
|
||||||
|
3 - add bcc address support
|
||||||
|
4 - add google analytics campaign support
|
||||||
|
5 - add tracking domain support
|
||||||
|
6 - add signing domain support
|
||||||
|
7 - add return path domainsupport
|
||||||
|
8 - add ip pool support
|
||||||
|
9 - add return path domain support
|
||||||
|
10 - add tags support
|
||||||
|
11 - add google analytics domains support
|
||||||
|
12 - add attachments support
|
||||||
|
13 - add metadata support
|
||||||
|
14 - add ip pool support
|
||||||
|
15 - add send at support
|
||||||
|
16 - add recipient metadata
|
||||||
|
*/
|
||||||
|
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'Mandrill',
|
||||||
|
name: 'mandrill',
|
||||||
|
icon: 'file:mandrill.png',
|
||||||
|
group: ['output'],
|
||||||
|
version: 1,
|
||||||
|
description: 'Sends an email via Mandrill',
|
||||||
|
defaults: {
|
||||||
|
name: 'Mandrill',
|
||||||
|
color: '#c02428',
|
||||||
|
},
|
||||||
|
inputs: ['main'],
|
||||||
|
outputs: ['main'],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'mandrillApi',
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Send template',
|
||||||
|
value: 'sendTemplate',
|
||||||
|
description: 'Send template',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Send html',
|
||||||
|
value: 'sendHtml',
|
||||||
|
description: 'Send Html',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'sendTemplate',
|
||||||
|
description: 'The operation to perform.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Template',
|
||||||
|
name: 'template',
|
||||||
|
type: 'options',
|
||||||
|
typeOptions: {
|
||||||
|
loadOptionsMethod: 'getTemplates',
|
||||||
|
},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'sendTemplate',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
options: [],
|
||||||
|
required: true,
|
||||||
|
description: 'The template you want to send',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'HTML',
|
||||||
|
name: 'html',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'sendHtml',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
typeOptions: {
|
||||||
|
rows: 5,
|
||||||
|
},
|
||||||
|
options: [],
|
||||||
|
required: true,
|
||||||
|
description: 'The html you want to send',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'From Email',
|
||||||
|
name: 'fromEmail',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
placeholder: 'Admin <example@yourdomain.com>',
|
||||||
|
description: 'Email address of the sender optional with name.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To Email',
|
||||||
|
name: 'toEmail',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
placeholder: 'info@example.com',
|
||||||
|
description: 'Email address of the recipient. Multiple ones can be separated by comma.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Subject',
|
||||||
|
name: 'subject',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: 'My subject line',
|
||||||
|
description: 'Subject line of the email.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Merge vars',
|
||||||
|
name: 'mergeVars',
|
||||||
|
type: 'json',
|
||||||
|
typeOptions: {
|
||||||
|
alwaysOpenEditWindow: true,
|
||||||
|
rows: 5,
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
placeholder: `mergeVars: [{
|
||||||
|
rcpt: 'example@example.com',
|
||||||
|
vars: [
|
||||||
|
{ name: 'name', content: 'content' }
|
||||||
|
]
|
||||||
|
}]`,
|
||||||
|
description: 'Per-recipient merge variables',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Important',
|
||||||
|
name: 'important',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not this message is important, and should be delivered ahead of non-important messages',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Track opens',
|
||||||
|
name: 'trackOpens',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to turn on open tracking for the message',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Track clicks',
|
||||||
|
name: 'trackClicks',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to turn on click tracking for the message',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Auto text',
|
||||||
|
name: 'autoText',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to automatically generate a text part for messages that are not given text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Auto HTML',
|
||||||
|
name: 'autoHtml',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to automatically generate an HTML part for messages that are not given HTML',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Inline css',
|
||||||
|
name: 'inlineCss',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to automatically inline all CSS styles provided in the message HTML - only for HTML documents less than 256KB in size',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Url strip qs',
|
||||||
|
name: 'urlStripQs',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to strip the query string from URLs when aggregating tracked URL data',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Preserve recipients',
|
||||||
|
name: 'preserveRecipients',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'whether or not to expose all recipients in to "To" header for each email',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'View content link',
|
||||||
|
name: 'viewContentLink',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'set to false to remove content logging for sensitive emails',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Async',
|
||||||
|
name: 'async',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: `enable a background sending mode that is optimized for bulk sending. In async mode, messages/send will immediately return a status of "queued" for every recipient. To handle rejections when sending in async mode, set up a webhook for the 'reject' event. Defaults to false for messages with no more than 10 recipients; messages with more than 10 recipients are always sent asynchronously, regardless of the value of async.`,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
methods = {
|
||||||
|
loadOptions: {
|
||||||
|
// Get all the available templates to display them to user so that he can
|
||||||
|
// select them easily
|
||||||
|
async getTemplates(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||||
|
const returnData: INodePropertyOptions[] = [];
|
||||||
|
let templates;
|
||||||
|
try {
|
||||||
|
templates = await mandrillApiRequest.call(this, '/templates', 'POST', '/list');
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Mandrill Error: ${err}`);
|
||||||
|
}
|
||||||
|
for (const template of templates) {
|
||||||
|
const templateName = template.name;
|
||||||
|
const templateSlug = template.slug
|
||||||
|
|
||||||
|
returnData.push({
|
||||||
|
name: templateName,
|
||||||
|
value: templateSlug,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
async executeSingle(this: IExecuteSingleFunctions): Promise<INodeExecutionData> {
|
||||||
|
|
||||||
|
const operation = this.getNodeParameter('operation') as string;
|
||||||
|
const fromEmail = this.getNodeParameter('fromEmail') as string;
|
||||||
|
const toEmail = this.getNodeParameter('toEmail') as string;
|
||||||
|
const subject = this.getNodeParameter('subject') as string;
|
||||||
|
const important = this.getNodeParameter('important') as boolean;
|
||||||
|
const trackOpens = this.getNodeParameter('trackOpens') as boolean;
|
||||||
|
const trackClicks = this.getNodeParameter('trackClicks') as boolean;
|
||||||
|
const autoText = this.getNodeParameter('autoText') as boolean;
|
||||||
|
const autoHtml = this.getNodeParameter('autoHtml') as boolean;
|
||||||
|
const inlineCss = this.getNodeParameter('inlineCss') as boolean;
|
||||||
|
const urlStripQs = this.getNodeParameter('urlStripQs') as boolean;
|
||||||
|
const preserveRecipients = this.getNodeParameter('preserveRecipients') as boolean;
|
||||||
|
const viewContentLink = this.getNodeParameter('viewContentLink') as boolean;
|
||||||
|
const async = this.getNodeParameter('async') as boolean;
|
||||||
|
const toEmailArray = getToEmailArray(toEmail)
|
||||||
|
|
||||||
|
const credentials = this.getCredentials('mandrillApi');
|
||||||
|
|
||||||
|
if (credentials === undefined) {
|
||||||
|
throw new Error('No credentials got returned!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const body: IDataObject = {
|
||||||
|
message: {
|
||||||
|
subject: subject,
|
||||||
|
from_email: fromEmail,
|
||||||
|
to: toEmailArray,
|
||||||
|
important: important,
|
||||||
|
track_opens: trackOpens,
|
||||||
|
track_clicks: trackClicks,
|
||||||
|
auto_text: autoText,
|
||||||
|
auto_html: autoHtml,
|
||||||
|
inline_css: inlineCss,
|
||||||
|
url_strip_qs: urlStripQs,
|
||||||
|
preserve_recipients: preserveRecipients,
|
||||||
|
view_content_link: viewContentLink,
|
||||||
|
async: async,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (operation === 'sendTemplate') {
|
||||||
|
const template = this.getNodeParameter('template') as string;
|
||||||
|
body.template_name = template
|
||||||
|
} else if (operation === 'sendHtml') {
|
||||||
|
const html = this.getNodeParameter('html') as string;
|
||||||
|
body.html = html
|
||||||
|
}
|
||||||
|
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
message = await mandrillApiRequest.call(this, '/messages', 'POST', '/send', body);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Mandrill Error: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
json: message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
BIN
packages/nodes-base/nodes/Mandrill/mandrill.png
Normal file
BIN
packages/nodes-base/nodes/Mandrill/mandrill.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -52,7 +52,8 @@
|
||||||
"dist/credentials/TelegramApi.credentials.js",
|
"dist/credentials/TelegramApi.credentials.js",
|
||||||
"dist/credentials/TrelloApi.credentials.js",
|
"dist/credentials/TrelloApi.credentials.js",
|
||||||
"dist/credentials/TwilioApi.credentials.js",
|
"dist/credentials/TwilioApi.credentials.js",
|
||||||
"dist/credentials/TypeformApi.credentials.js"
|
"dist/credentials/TypeformApi.credentials.js",
|
||||||
|
"dist/credentials/MandrillApi.credentials.js"
|
||||||
],
|
],
|
||||||
"nodes": [
|
"nodes": [
|
||||||
"dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
|
"dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
|
||||||
|
@ -108,7 +109,8 @@
|
||||||
"dist/nodes/Typeform/TypeformTrigger.node.js",
|
"dist/nodes/Typeform/TypeformTrigger.node.js",
|
||||||
"dist/nodes/WriteBinaryFile.node.js",
|
"dist/nodes/WriteBinaryFile.node.js",
|
||||||
"dist/nodes/Webhook.node.js",
|
"dist/nodes/Webhook.node.js",
|
||||||
"dist/nodes/Xml.node.js"
|
"dist/nodes/Xml.node.js",
|
||||||
|
"dist/nodes/Mandrill/Mandrill.node.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
Loading…
Reference in a new issue