mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -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/TrelloApi.credentials.js",
|
||||
"dist/credentials/TwilioApi.credentials.js",
|
||||
"dist/credentials/TypeformApi.credentials.js"
|
||||
"dist/credentials/TypeformApi.credentials.js",
|
||||
"dist/credentials/MandrillApi.credentials.js"
|
||||
],
|
||||
"nodes": [
|
||||
"dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
|
||||
|
@ -108,7 +109,8 @@
|
|||
"dist/nodes/Typeform/TypeformTrigger.node.js",
|
||||
"dist/nodes/WriteBinaryFile.node.js",
|
||||
"dist/nodes/Webhook.node.js",
|
||||
"dist/nodes/Xml.node.js"
|
||||
"dist/nodes/Xml.node.js",
|
||||
"dist/nodes/Mandrill/Mandrill.node.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
Loading…
Reference in a new issue