n8n-nodes-gmail-custom 0.5.1 → 0.6.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,238 @@
|
|
|
1
|
+
const { getOrRefreshAccessToken } = require('./utils');
|
|
2
|
+
|
|
3
|
+
class GmailGetCustom {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.description = {
|
|
6
|
+
displayName: 'Gmail Get Custom',
|
|
7
|
+
name: 'gmailGetCustom',
|
|
8
|
+
icon: 'fa:envelope',
|
|
9
|
+
group: ['output'],
|
|
10
|
+
version: 1,
|
|
11
|
+
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
|
|
12
|
+
description: 'Get a Message or Thread from Gmail with token caching',
|
|
13
|
+
defaults: {
|
|
14
|
+
name: 'Gmail Get Custom',
|
|
15
|
+
color: '#1a73e8',
|
|
16
|
+
},
|
|
17
|
+
inputs: ['main'],
|
|
18
|
+
outputs: ['main'],
|
|
19
|
+
properties: [
|
|
20
|
+
{
|
|
21
|
+
displayName: 'Service Account Email',
|
|
22
|
+
name: 'serviceAccountEmail',
|
|
23
|
+
type: 'string',
|
|
24
|
+
default: '',
|
|
25
|
+
required: true,
|
|
26
|
+
placeholder: 'sa-name@project.iam.gserviceaccount.com',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
displayName: 'Private Key',
|
|
30
|
+
name: 'privateKey',
|
|
31
|
+
type: 'string',
|
|
32
|
+
typeOptions: { password: true },
|
|
33
|
+
default: '',
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
displayName: 'Delegated Email',
|
|
38
|
+
name: 'delegatedEmail',
|
|
39
|
+
type: 'string',
|
|
40
|
+
default: '',
|
|
41
|
+
required: true,
|
|
42
|
+
placeholder: 'user@domain.com',
|
|
43
|
+
description: 'The Gmail mailbox to access (user to impersonate)',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
displayName: 'Resource',
|
|
47
|
+
name: 'resource',
|
|
48
|
+
type: 'options',
|
|
49
|
+
noDataExpression: true,
|
|
50
|
+
options: [
|
|
51
|
+
{ name: 'Message', value: 'message' },
|
|
52
|
+
{ name: 'Thread', value: 'thread' },
|
|
53
|
+
],
|
|
54
|
+
default: 'message',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
displayName: 'Operation',
|
|
58
|
+
name: 'operation',
|
|
59
|
+
type: 'options',
|
|
60
|
+
noDataExpression: true,
|
|
61
|
+
options: [{ name: 'Get', value: 'get' }],
|
|
62
|
+
default: 'get',
|
|
63
|
+
displayOptions: {
|
|
64
|
+
show: { resource: ['message'] },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
displayName: 'Operation',
|
|
69
|
+
name: 'operation',
|
|
70
|
+
type: 'options',
|
|
71
|
+
noDataExpression: true,
|
|
72
|
+
options: [{ name: 'Get', value: 'get' }],
|
|
73
|
+
default: 'get',
|
|
74
|
+
displayOptions: {
|
|
75
|
+
show: { resource: ['thread'] },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
displayName: 'Message ID',
|
|
80
|
+
name: 'messageId',
|
|
81
|
+
type: 'string',
|
|
82
|
+
default: '',
|
|
83
|
+
required: true,
|
|
84
|
+
displayOptions: {
|
|
85
|
+
show: { resource: ['message'] },
|
|
86
|
+
},
|
|
87
|
+
placeholder: '172ce2c4a72cc243',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
displayName: 'Thread ID',
|
|
91
|
+
name: 'threadId',
|
|
92
|
+
type: 'string',
|
|
93
|
+
default: '',
|
|
94
|
+
required: true,
|
|
95
|
+
displayOptions: {
|
|
96
|
+
show: { resource: ['thread'] },
|
|
97
|
+
},
|
|
98
|
+
placeholder: '172ce2c4a72cc243',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
displayName: 'Simplify',
|
|
102
|
+
name: 'simple',
|
|
103
|
+
type: 'boolean',
|
|
104
|
+
default: true,
|
|
105
|
+
displayOptions: {
|
|
106
|
+
show: { resource: ['message', 'thread'] },
|
|
107
|
+
},
|
|
108
|
+
description: 'Whether to return a simplified version (metadata headers only) instead of raw data',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
displayName: 'Options',
|
|
112
|
+
name: 'options',
|
|
113
|
+
type: 'collection',
|
|
114
|
+
placeholder: 'Add option',
|
|
115
|
+
default: {},
|
|
116
|
+
displayOptions: {
|
|
117
|
+
show: { resource: ['thread'] },
|
|
118
|
+
},
|
|
119
|
+
options: [
|
|
120
|
+
{
|
|
121
|
+
displayName: 'Return Only Messages',
|
|
122
|
+
name: 'returnOnlyMessages',
|
|
123
|
+
type: 'boolean',
|
|
124
|
+
default: false,
|
|
125
|
+
description: 'Whether to return only the messages array without thread metadata',
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async execute() {
|
|
134
|
+
const items = this.getInputData();
|
|
135
|
+
if (!items || items.length === 0) {
|
|
136
|
+
return [[]];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const returnData = [];
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < items.length; i++) {
|
|
142
|
+
try {
|
|
143
|
+
const serviceAccountEmail = this.getNodeParameter('serviceAccountEmail', i, '');
|
|
144
|
+
const privateKey = this.getNodeParameter('privateKey', i, '');
|
|
145
|
+
const delegatedEmail = this.getNodeParameter('delegatedEmail', i, '');
|
|
146
|
+
const resource = this.getNodeParameter('resource', i, 'message');
|
|
147
|
+
const simple = this.getNodeParameter('simple', i, true);
|
|
148
|
+
const options = this.getNodeParameter('options', i, {});
|
|
149
|
+
|
|
150
|
+
const accessToken = await getOrRefreshAccessToken(this, serviceAccountEmail, privateKey, delegatedEmail);
|
|
151
|
+
|
|
152
|
+
const qs = {};
|
|
153
|
+
if (simple) {
|
|
154
|
+
qs.format = 'metadata';
|
|
155
|
+
qs.metadataHeaders = ['From', 'To', 'Cc', 'Bcc', 'Subject'];
|
|
156
|
+
} else {
|
|
157
|
+
qs.format = resource === 'thread' ? 'full' : 'raw';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let url;
|
|
161
|
+
if (resource === 'message') {
|
|
162
|
+
const messageId = this.getNodeParameter('messageId', i, '');
|
|
163
|
+
if (!messageId) throw new Error('Message ID is required');
|
|
164
|
+
url = `https://gmail.googleapis.com/gmail/v1/users/me/messages/${messageId}`;
|
|
165
|
+
} else {
|
|
166
|
+
const threadId = this.getNodeParameter('threadId', i, '');
|
|
167
|
+
if (!threadId) throw new Error('Thread ID is required');
|
|
168
|
+
url = `https://gmail.googleapis.com/gmail/v1/users/me/threads/${threadId}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const response = await this.helpers.httpRequest({
|
|
172
|
+
method: 'GET',
|
|
173
|
+
url,
|
|
174
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
175
|
+
qs,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
let result;
|
|
179
|
+
if (resource === 'thread') {
|
|
180
|
+
if (simple) {
|
|
181
|
+
if (response.messages) {
|
|
182
|
+
response.messages = response.messages.map((msg) => {
|
|
183
|
+
const flat = { ...msg };
|
|
184
|
+
if (flat.payload && flat.payload.headers) {
|
|
185
|
+
for (const h of flat.payload.headers) {
|
|
186
|
+
flat[h.name] = h.value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return flat;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (options.returnOnlyMessages) {
|
|
195
|
+
result = response.messages || [];
|
|
196
|
+
} else {
|
|
197
|
+
result = { json: response };
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
// Message
|
|
201
|
+
if (simple && response.payload && response.payload.headers) {
|
|
202
|
+
for (const h of response.payload.headers) {
|
|
203
|
+
response[h.name] = h.value;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
result = { json: response };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const isArray = Array.isArray(result);
|
|
210
|
+
if (isArray) {
|
|
211
|
+
for (const item of result) {
|
|
212
|
+
returnData.push({ json: item, pairedItem: { item: i } });
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
returnData.push({ ...result, pairedItem: { item: i } });
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
let continueOnFail = false;
|
|
219
|
+
try { continueOnFail = this.continueOnFail(); } catch (e) {}
|
|
220
|
+
if (continueOnFail) {
|
|
221
|
+
returnData.push({
|
|
222
|
+
json: { error: error.message || 'Unknown error' },
|
|
223
|
+
pairedItem: { item: i },
|
|
224
|
+
});
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return [returnData];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
module.exports = {
|
|
236
|
+
nodeTypes: [GmailGetCustom],
|
|
237
|
+
GmailGetCustom,
|
|
238
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-gmail-custom",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Custom Gmail nodes for n8n
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Custom Gmail nodes for n8n — Send, Trigger, Get (Message+Thread) — token caching, self-contained",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
7
7
|
"n8n",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"credentials": [],
|
|
21
21
|
"nodes": [
|
|
22
22
|
"nodes/GmailCustom/GmailCustom.node.js",
|
|
23
|
-
"nodes/GmailCustom/GmailTriggerCustom.node.js"
|
|
23
|
+
"nodes/GmailCustom/GmailTriggerCustom.node.js",
|
|
24
|
+
"nodes/GmailCustom/GmailGetCustom.node.js"
|
|
24
25
|
]
|
|
25
26
|
}
|
|
26
27
|
}
|