@estaldo/n8n-nodes-postmarkapp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostmarkEmail = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const descriptions_1 = require("./descriptions");
6
+ const helpers_1 = require("./helpers");
7
+ const operations_1 = require("./operations");
8
+ const POSTMARK_BASE_URL = 'https://api.postmarkapp.com';
9
+ class PostmarkEmail {
10
+ description = {
11
+ displayName: 'Postmark Email',
12
+ name: 'postmarkEmail',
13
+ icon: 'file:postmarkEmail.svg',
14
+ group: ['output'],
15
+ version: 1,
16
+ description: 'Send transactional email via Postmark',
17
+ defaults: {
18
+ name: 'Postmark Email',
19
+ },
20
+ inputs: ['main'],
21
+ outputs: ['main'],
22
+ credentials: [
23
+ {
24
+ name: 'postmarkApi',
25
+ required: true,
26
+ },
27
+ ],
28
+ properties: descriptions_1.ALL_PROPERTIES,
29
+ };
30
+ async execute() {
31
+ const items = this.getInputData();
32
+ const out = [];
33
+ for (let i = 0; i < items.length; i++) {
34
+ const operation = this.getNodeParameter('operation', i);
35
+ const path = operations_1.OPERATION_ENDPOINTS[operation];
36
+ if (!path) {
37
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`, { itemIndex: i });
38
+ }
39
+ const defaultStream = this.getNodeParameter('messageStream', i, '');
40
+ let body;
41
+ if (operation === operations_1.Operation.Send || operation === operations_1.Operation.SendWithTemplate) {
42
+ const kind = operation === operations_1.Operation.SendWithTemplate ? 'templated' : 'plain';
43
+ const source = (0, helpers_1.collectSingleMessage)(this, i, kind);
44
+ body = (0, helpers_1.buildEmailBody)(this, i, source, kind);
45
+ (0, helpers_1.applyDefaultMessageStream)(body, defaultStream);
46
+ }
47
+ else {
48
+ const kind = operation === operations_1.Operation.SendBatchWithTemplates ? 'templated' : 'plain';
49
+ const messages = (0, helpers_1.collectBatchMessages)(this, i, kind);
50
+ if (messages.length === 0) {
51
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one message is required for a batch send', { itemIndex: i });
52
+ }
53
+ const messageBodies = messages.map((msg) => {
54
+ const built = (0, helpers_1.buildEmailBody)(this, i, msg, kind);
55
+ (0, helpers_1.applyDefaultMessageStream)(built, defaultStream);
56
+ return built;
57
+ });
58
+ // Postmark's two batch endpoints differ in body shape:
59
+ // - /email/batch → bare JSON array `[ {...}, {...} ]`.
60
+ // - /email/batchWithTemplates → `{ "Messages": [ {...} ] }` (property name in
61
+ // the body, not a path component).
62
+ body = operation === operations_1.Operation.SendBatchWithTemplates
63
+ ? { Messages: messageBodies }
64
+ : messageBodies;
65
+ }
66
+ let response;
67
+ try {
68
+ response = (await this.helpers.httpRequestWithAuthentication.call(this, 'postmarkApi', {
69
+ method: 'POST',
70
+ url: `${POSTMARK_BASE_URL}${path}`,
71
+ body,
72
+ json: true,
73
+ }));
74
+ }
75
+ catch (err) {
76
+ throw (0, helpers_1.wrapPostmarkError)(this, err, i);
77
+ }
78
+ out.push({ json: response, pairedItem: { item: i } });
79
+ }
80
+ return [out];
81
+ }
82
+ }
83
+ exports.PostmarkEmail = PostmarkEmail;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendEmailBatchProperty = void 0;
4
+ const operations_1 = require("../operations");
5
+ const additionalFields_1 = require("./additionalFields");
6
+ const BATCH_PLAIN_MESSAGE_VALUES = [
7
+ {
8
+ displayName: 'From',
9
+ name: 'from',
10
+ type: 'string',
11
+ default: '',
12
+ required: true,
13
+ placeholder: 'sender@example.com',
14
+ description: 'Sender email address',
15
+ },
16
+ {
17
+ displayName: 'To',
18
+ name: 'to',
19
+ type: 'string',
20
+ default: '',
21
+ required: true,
22
+ placeholder: 'recipient@example.com',
23
+ description: 'Recipient email address. Comma-separate for multiple recipients (max 50 per request).',
24
+ },
25
+ {
26
+ displayName: 'Subject',
27
+ name: 'subject',
28
+ type: 'string',
29
+ default: '',
30
+ required: true,
31
+ description: 'Email subject line',
32
+ },
33
+ {
34
+ displayName: 'HTML Body',
35
+ name: 'htmlBody',
36
+ type: 'string',
37
+ typeOptions: { rows: 6 },
38
+ default: '',
39
+ description: 'HTML body of the email. At least one of HTML Body or Text Body is required.',
40
+ },
41
+ {
42
+ displayName: 'Text Body',
43
+ name: 'textBody',
44
+ type: 'string',
45
+ typeOptions: { rows: 4 },
46
+ default: '',
47
+ description: 'Plain text body of the email. At least one of HTML Body or Text Body is required.',
48
+ },
49
+ // Optional fields spread directly inline — workflow authors fill what they want
50
+ // without first clicking "Add Field" inside each batch message.
51
+ ...additionalFields_1.OPTIONAL_EMAIL_FIELDS,
52
+ ];
53
+ exports.sendEmailBatchProperty = {
54
+ displayName: 'Messages',
55
+ name: 'batchMessages',
56
+ type: 'fixedCollection',
57
+ default: {},
58
+ placeholder: 'Add Message',
59
+ typeOptions: { multipleValues: true, sortable: true },
60
+ description: 'Emails to send in this batch. Each message is sent as one email.',
61
+ displayOptions: {
62
+ show: {
63
+ operation: [operations_1.Operation.SendBatch],
64
+ },
65
+ },
66
+ options: [
67
+ {
68
+ name: 'message',
69
+ displayName: 'Message',
70
+ values: BATCH_PLAIN_MESSAGE_VALUES,
71
+ },
72
+ ],
73
+ };
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendEmailBatchWithTemplatesProperty = void 0;
4
+ const operations_1 = require("../operations");
5
+ const additionalFields_1 = require("./additionalFields");
6
+ const BATCH_TEMPLATED_MESSAGE_VALUES = [
7
+ {
8
+ displayName: 'From',
9
+ name: 'from',
10
+ type: 'string',
11
+ default: '',
12
+ required: true,
13
+ placeholder: 'sender@example.com',
14
+ description: 'Sender email address',
15
+ },
16
+ {
17
+ displayName: 'To',
18
+ name: 'to',
19
+ type: 'string',
20
+ default: '',
21
+ required: true,
22
+ placeholder: 'recipient@example.com',
23
+ description: 'Recipient email address. Comma-separate for multiple recipients (max 50 per request).',
24
+ },
25
+ {
26
+ displayName: 'Template Source',
27
+ name: 'templateSource',
28
+ type: 'options',
29
+ default: 'alias',
30
+ options: [
31
+ { name: 'Alias', value: 'alias' },
32
+ { name: 'ID', value: 'id' },
33
+ ],
34
+ description: 'How to identify the template',
35
+ },
36
+ {
37
+ displayName: 'Template ID',
38
+ name: 'templateId',
39
+ type: 'string',
40
+ default: '',
41
+ required: true,
42
+ placeholder: 'welcome-email or 12345',
43
+ description: 'Template alias (string) or numeric ID, depending on Template Source',
44
+ },
45
+ {
46
+ displayName: 'Template Model',
47
+ name: 'templateModel',
48
+ type: 'json',
49
+ default: '{}',
50
+ description: 'JSON object of values to merge into the template',
51
+ },
52
+ // Optional fields spread directly inline — workflow authors fill what they want
53
+ // without first clicking "Add Field" inside each batch message.
54
+ ...additionalFields_1.OPTIONAL_EMAIL_FIELDS,
55
+ ];
56
+ exports.sendEmailBatchWithTemplatesProperty = {
57
+ displayName: 'Messages',
58
+ name: 'batchMessagesWithTemplates',
59
+ type: 'fixedCollection',
60
+ default: {},
61
+ placeholder: 'Add Message',
62
+ typeOptions: { multipleValues: true, sortable: true },
63
+ description: 'Templated emails to send in this batch. Each message is rendered from its template and sent as one email.',
64
+ displayOptions: {
65
+ show: {
66
+ operation: [operations_1.Operation.SendBatchWithTemplates],
67
+ },
68
+ },
69
+ options: [
70
+ {
71
+ name: 'message',
72
+ displayName: 'Message',
73
+ values: BATCH_TEMPLATED_MESSAGE_VALUES,
74
+ },
75
+ ],
76
+ };
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendEmailSingleProperties = void 0;
4
+ const operations_1 = require("../operations");
5
+ // Top-level fields for the `send` operation.
6
+ // From and To are shared with `sendWithTemplate` (their displayOptions cover both single
7
+ // ops). Subject / HTML Body / Text Body are specific to `send`.
8
+ exports.sendEmailSingleProperties = [
9
+ {
10
+ displayName: 'From',
11
+ name: 'from',
12
+ type: 'string',
13
+ default: '',
14
+ required: true,
15
+ placeholder: 'sender@example.com',
16
+ description: 'Sender email address',
17
+ displayOptions: {
18
+ show: {
19
+ operation: [operations_1.Operation.Send, operations_1.Operation.SendWithTemplate],
20
+ },
21
+ },
22
+ },
23
+ {
24
+ displayName: 'To',
25
+ name: 'to',
26
+ type: 'string',
27
+ default: '',
28
+ required: true,
29
+ placeholder: 'recipient@example.com',
30
+ description: 'Recipient email address. Comma-separate for multiple recipients (max 50 per request).',
31
+ displayOptions: {
32
+ show: {
33
+ operation: [operations_1.Operation.Send, operations_1.Operation.SendWithTemplate],
34
+ },
35
+ },
36
+ },
37
+ {
38
+ displayName: 'Subject',
39
+ name: 'subject',
40
+ type: 'string',
41
+ default: '',
42
+ required: true,
43
+ description: 'Email subject line',
44
+ displayOptions: {
45
+ show: {
46
+ operation: [operations_1.Operation.Send],
47
+ },
48
+ },
49
+ },
50
+ {
51
+ displayName: 'HTML Body',
52
+ name: 'htmlBody',
53
+ type: 'string',
54
+ typeOptions: { rows: 6 },
55
+ default: '',
56
+ description: 'HTML body of the email. At least one of HTML Body or Text Body is required.',
57
+ displayOptions: {
58
+ show: {
59
+ operation: [operations_1.Operation.Send],
60
+ },
61
+ },
62
+ },
63
+ {
64
+ displayName: 'Text Body',
65
+ name: 'textBody',
66
+ type: 'string',
67
+ typeOptions: { rows: 4 },
68
+ default: '',
69
+ description: 'Plain text body of the email. At least one of HTML Body or Text Body is required.',
70
+ displayOptions: {
71
+ show: {
72
+ operation: [operations_1.Operation.Send],
73
+ },
74
+ },
75
+ },
76
+ ];
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendEmailSingleWithTemplateProperties = void 0;
4
+ const operations_1 = require("../operations");
5
+ // Top-level fields specific to the `sendWithTemplate` operation. From and To live in
6
+ // SendEmailSingle.ts because they are shared with the plain `send` operation.
7
+ exports.sendEmailSingleWithTemplateProperties = [
8
+ {
9
+ displayName: 'Template Source',
10
+ name: 'templateSource',
11
+ type: 'options',
12
+ default: 'alias',
13
+ options: [
14
+ { name: 'Alias', value: 'alias' },
15
+ { name: 'ID', value: 'id' },
16
+ ],
17
+ description: 'How to identify the template',
18
+ displayOptions: {
19
+ show: {
20
+ operation: [operations_1.Operation.SendWithTemplate],
21
+ },
22
+ },
23
+ },
24
+ {
25
+ displayName: 'Template ID',
26
+ name: 'templateId',
27
+ type: 'string',
28
+ default: '',
29
+ required: true,
30
+ placeholder: 'welcome-email or 12345',
31
+ description: 'Template alias (string) or numeric ID, depending on Template Source',
32
+ displayOptions: {
33
+ show: {
34
+ operation: [operations_1.Operation.SendWithTemplate],
35
+ },
36
+ },
37
+ },
38
+ {
39
+ displayName: 'Template Model',
40
+ name: 'templateModel',
41
+ type: 'json',
42
+ default: '{}',
43
+ description: 'JSON object of values to merge into the template',
44
+ displayOptions: {
45
+ show: {
46
+ operation: [operations_1.Operation.SendWithTemplate],
47
+ },
48
+ },
49
+ },
50
+ ];
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OPTIONAL_EMAIL_FIELDS = void 0;
4
+ // Optional Postmark body fields. Spread directly into the editor (top-level for single
5
+ // send/sendWithTemplate, nested inside per-message values for batch ops) so workflow
6
+ // authors don't have to click "Add Field" before they can fill in Cc, Tag, Headers,
7
+ // etc. — particularly painful when configuring batch messages.
8
+ exports.OPTIONAL_EMAIL_FIELDS = [
9
+ {
10
+ displayName: 'Cc',
11
+ name: 'Cc',
12
+ type: 'string',
13
+ default: '',
14
+ description: 'Carbon-copy recipient email address(es), comma-separated',
15
+ },
16
+ {
17
+ displayName: 'Bcc',
18
+ name: 'Bcc',
19
+ type: 'string',
20
+ default: '',
21
+ description: 'Blind-carbon-copy recipient email address(es), comma-separated',
22
+ },
23
+ {
24
+ displayName: 'Reply To',
25
+ name: 'ReplyTo',
26
+ type: 'string',
27
+ default: '',
28
+ description: 'Reply-To email address override',
29
+ },
30
+ {
31
+ displayName: 'Message Stream',
32
+ name: 'MessageStream',
33
+ type: 'string',
34
+ default: '',
35
+ placeholder: 'outbound',
36
+ description: 'Per-message Postmark message stream ID. Overrides the top-level Message Stream parameter for this message only.',
37
+ },
38
+ {
39
+ displayName: 'Tag',
40
+ name: 'Tag',
41
+ type: 'string',
42
+ default: '',
43
+ description: 'Tag for grouping in stats and webhooks',
44
+ },
45
+ {
46
+ displayName: 'Track Opens',
47
+ name: 'TrackOpens',
48
+ type: 'boolean',
49
+ default: false,
50
+ description: 'Whether to track email opens (HTML emails only)',
51
+ },
52
+ {
53
+ displayName: 'Track Links',
54
+ name: 'TrackLinks',
55
+ type: 'options',
56
+ default: 'None',
57
+ description: 'Click tracking mode for links in the email body',
58
+ options: [
59
+ { name: 'None', value: 'None' },
60
+ { name: 'HTML and Text', value: 'HtmlAndText' },
61
+ { name: 'HTML Only', value: 'HtmlOnly' },
62
+ { name: 'Text Only', value: 'TextOnly' },
63
+ ],
64
+ },
65
+ {
66
+ displayName: 'Headers',
67
+ name: 'Headers',
68
+ type: 'fixedCollection',
69
+ default: {},
70
+ placeholder: 'Add Header',
71
+ typeOptions: { multipleValues: true },
72
+ description: 'Custom email headers',
73
+ options: [
74
+ {
75
+ name: 'header',
76
+ displayName: 'Header',
77
+ values: [
78
+ {
79
+ displayName: 'Name',
80
+ name: 'Name',
81
+ type: 'string',
82
+ default: '',
83
+ placeholder: 'X-Custom-Header',
84
+ description: 'Header name',
85
+ },
86
+ {
87
+ displayName: 'Value',
88
+ name: 'Value',
89
+ type: 'string',
90
+ default: '',
91
+ description: 'Header value',
92
+ },
93
+ ],
94
+ },
95
+ ],
96
+ },
97
+ {
98
+ displayName: 'Metadata',
99
+ name: 'Metadata',
100
+ type: 'fixedCollection',
101
+ default: {},
102
+ placeholder: 'Add Metadata Pair',
103
+ typeOptions: { multipleValues: true },
104
+ description: 'Custom metadata pairs attached to the email (visible in webhook payloads)',
105
+ options: [
106
+ {
107
+ name: 'pair',
108
+ displayName: 'Pair',
109
+ values: [
110
+ { displayName: 'Key', name: 'key', type: 'string', default: '' },
111
+ { displayName: 'Value', name: 'value', type: 'string', default: '' },
112
+ ],
113
+ },
114
+ ],
115
+ },
116
+ {
117
+ displayName: 'Attachments',
118
+ name: 'Attachments',
119
+ type: 'fixedCollection',
120
+ default: {},
121
+ placeholder: 'Add Attachment',
122
+ typeOptions: { multipleValues: true },
123
+ description: 'File attachments',
124
+ options: [
125
+ {
126
+ name: 'attachment',
127
+ displayName: 'Attachment',
128
+ values: [
129
+ {
130
+ displayName: 'Name',
131
+ name: 'Name',
132
+ type: 'string',
133
+ default: '',
134
+ placeholder: 'invoice.pdf',
135
+ description: 'Filename to display in the recipient\'s email client',
136
+ },
137
+ {
138
+ displayName: 'Content',
139
+ name: 'Content',
140
+ type: 'string',
141
+ typeOptions: { rows: 4 },
142
+ default: '',
143
+ description: 'Base64-encoded file content. From a previous binary node, use {{ $binary.data.toString("base64") }}.',
144
+ },
145
+ {
146
+ displayName: 'Content Type',
147
+ name: 'ContentType',
148
+ type: 'string',
149
+ default: '',
150
+ placeholder: 'application/pdf',
151
+ description: 'MIME type of the attachment, e.g. application/pdf or image/png',
152
+ },
153
+ {
154
+ displayName: 'Content ID',
155
+ name: 'ContentID',
156
+ type: 'string',
157
+ default: '',
158
+ placeholder: 'cid:image1',
159
+ description: 'Optional. For inline images, set to "cid:imageId" and reference in HTML body via &lt;img src="cid:imageId" /&gt;.',
160
+ },
161
+ ],
162
+ },
163
+ ],
164
+ },
165
+ ];
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ALL_PROPERTIES = void 0;
4
+ const operation_1 = require("./operation");
5
+ const SendEmailSingle_1 = require("./SendEmailSingle");
6
+ const SendEmailSingleWithTemplate_1 = require("./SendEmailSingleWithTemplate");
7
+ const SendEmailBatch_1 = require("./SendEmailBatch");
8
+ const SendEmailBatchWithTemplates_1 = require("./SendEmailBatchWithTemplates");
9
+ const sharedFields_1 = require("./sharedFields");
10
+ // Order matters for the editor: it concatenates the visible properties top-to-bottom.
11
+ // Particularly: singleOptionalFields must come *after* the template fields so they
12
+ // render below the Template fields for `sendWithTemplate` (rather than between
13
+ // From/To and the Template fields).
14
+ exports.ALL_PROPERTIES = [
15
+ operation_1.operationProperty,
16
+ ...SendEmailSingle_1.sendEmailSingleProperties,
17
+ ...SendEmailSingleWithTemplate_1.sendEmailSingleWithTemplateProperties,
18
+ ...sharedFields_1.singleOptionalFields,
19
+ SendEmailBatch_1.sendEmailBatchProperty,
20
+ SendEmailBatchWithTemplates_1.sendEmailBatchWithTemplatesProperty,
21
+ sharedFields_1.messageStreamProperty,
22
+ ];
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.operationProperty = void 0;
4
+ const operations_1 = require("../operations");
5
+ // The n8n linter's static analysis doesn't recognize `Operation.Send` as a literal default,
6
+ // so it raises `node-param-default-missing` on this object. The default *is* set — suppress
7
+ // the false positive rather than duplicating the value as a magic string.
8
+ // eslint-disable-next-line n8n-nodes-base/node-param-default-missing
9
+ exports.operationProperty = {
10
+ displayName: 'Operation',
11
+ name: 'operation',
12
+ type: 'options',
13
+ noDataExpression: true,
14
+ default: operations_1.Operation.Send,
15
+ options: [
16
+ {
17
+ name: 'Send',
18
+ value: operations_1.Operation.Send,
19
+ action: 'Send a single email',
20
+ },
21
+ {
22
+ name: 'Send With Template',
23
+ value: operations_1.Operation.SendWithTemplate,
24
+ action: 'Send a single templated email',
25
+ },
26
+ {
27
+ name: 'Send Batch',
28
+ value: operations_1.Operation.SendBatch,
29
+ action: 'Send multiple emails in one request',
30
+ },
31
+ {
32
+ name: 'Send Batch With Templates',
33
+ value: operations_1.Operation.SendBatchWithTemplates,
34
+ action: 'Send multiple templated emails in one request',
35
+ },
36
+ ],
37
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.messageStreamProperty = exports.singleOptionalFields = void 0;
4
+ const operations_1 = require("../operations");
5
+ const additionalFields_1 = require("./additionalFields");
6
+ // Single-ops top-level optional fields: the same fields the batch per-message values
7
+ // expose, but with displayOptions injected so they only render for `send` and
8
+ // `sendWithTemplate`. MessageStream is excluded — the dedicated top-level
9
+ // `messageStream` parameter (defined below) handles that case for single ops.
10
+ //
11
+ // Order matters in the editor: this set spreads *after* the template fields so that
12
+ // for `sendWithTemplate` the optional fields render below the Template fields rather
13
+ // than between From/To and them.
14
+ exports.singleOptionalFields = additionalFields_1.OPTIONAL_EMAIL_FIELDS
15
+ .filter((field) => field.name !== 'MessageStream')
16
+ .map((field) => ({
17
+ ...field,
18
+ displayOptions: {
19
+ show: {
20
+ operation: [operations_1.Operation.Send, operations_1.Operation.SendWithTemplate],
21
+ },
22
+ },
23
+ }));
24
+ exports.messageStreamProperty = {
25
+ displayName: 'Message Stream',
26
+ name: 'messageStream',
27
+ type: 'string',
28
+ default: '',
29
+ placeholder: 'outbound',
30
+ description: 'Message stream ID used for sending. Leave empty to use the default outbound transactional stream. For batch operations, applied as a default to each message that does not specify its own Message Stream override.',
31
+ };