n8n-nodes-gmail-custom 0.1.8 → 0.2.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.
|
@@ -161,6 +161,58 @@ async function buildMimeMessage(options) {
|
|
|
161
161
|
.replace(/=+$/, '');
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
async function getOrRefreshAccessToken(ctx, credentials, fromEmail) {
|
|
165
|
+
const cacheKey = `${credentials.email}:${fromEmail}`;
|
|
166
|
+
let token = TOKEN_CACHE[cacheKey];
|
|
167
|
+
if (token && token.expiresAt > Date.now()) {
|
|
168
|
+
return token.accessToken;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const privateKey = formatPrivateKey(credentials.privateKey);
|
|
172
|
+
const now = Math.floor(Date.now() / 1000);
|
|
173
|
+
|
|
174
|
+
let jwt;
|
|
175
|
+
const payload = {
|
|
176
|
+
iss: credentials.email,
|
|
177
|
+
scope: 'https://mail.google.com/',
|
|
178
|
+
aud: 'https://oauth2.googleapis.com/token',
|
|
179
|
+
exp: now + 3600,
|
|
180
|
+
iat: now,
|
|
181
|
+
sub: fromEmail,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
if (jwtLib) {
|
|
185
|
+
jwt = jwtLib.sign(payload, privateKey, {
|
|
186
|
+
algorithm: 'RS256',
|
|
187
|
+
header: { kid: privateKey, typ: 'JWT', alg: 'RS256' },
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
const header = { alg: 'RS256', typ: 'JWT', kid: privateKey };
|
|
191
|
+
const signatureInput = base64UrlEncode(JSON.stringify(header)) + '.' + base64UrlEncode(JSON.stringify(payload));
|
|
192
|
+
const signer = crypto.createSign('RSA-SHA256');
|
|
193
|
+
signer.update(signatureInput);
|
|
194
|
+
const sig = signer.sign(privateKey);
|
|
195
|
+
jwt = signatureInput + '.' + base64urlEscape(sig.toString('base64'));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const response = await ctx.helpers.httpRequest({
|
|
199
|
+
method: 'POST',
|
|
200
|
+
url: 'https://oauth2.googleapis.com/token',
|
|
201
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
202
|
+
body: new URLSearchParams({
|
|
203
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
204
|
+
assertion: jwt,
|
|
205
|
+
}).toString(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
TOKEN_CACHE[cacheKey] = {
|
|
209
|
+
accessToken: response.access_token,
|
|
210
|
+
expiresAt: Date.now() + 3500 * 1000,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return response.access_token;
|
|
214
|
+
}
|
|
215
|
+
|
|
164
216
|
class GmailCustom {
|
|
165
217
|
|
|
166
218
|
constructor() {
|
|
@@ -306,10 +358,15 @@ class GmailCustom {
|
|
|
306
358
|
|
|
307
359
|
async execute() {
|
|
308
360
|
const items = this.getInputData();
|
|
361
|
+
if (!items || items.length === 0) {
|
|
362
|
+
return [[]];
|
|
363
|
+
}
|
|
364
|
+
|
|
309
365
|
const returnData = [];
|
|
310
366
|
|
|
311
367
|
for (let i = 0; i < items.length; i++) {
|
|
312
368
|
try {
|
|
369
|
+
const item = items[i];
|
|
313
370
|
const fromEmail = this.getNodeParameter('fromEmail', i, '');
|
|
314
371
|
const sendTo = this.getNodeParameter('sendTo', i, '');
|
|
315
372
|
const subject = this.getNodeParameter('subject', i, '');
|
|
@@ -339,83 +396,15 @@ class GmailCustom {
|
|
|
339
396
|
}
|
|
340
397
|
|
|
341
398
|
if (appendAttribution) {
|
|
342
|
-
const attributionText = '\n\n---\nThis email was sent automatically with n8n';
|
|
343
399
|
if (emailType === 'html') {
|
|
344
400
|
bodyHtml += '<br><br>---<br><em>This email was sent automatically with n8n</em>';
|
|
345
401
|
} else {
|
|
346
|
-
bodyText +=
|
|
402
|
+
bodyText += '\n\n---\nThis email was sent automatically with n8n';
|
|
347
403
|
}
|
|
348
404
|
}
|
|
349
405
|
|
|
350
406
|
const credentials = await this.getCredentials('googleApi');
|
|
351
|
-
const
|
|
352
|
-
let accessToken;
|
|
353
|
-
let expiresAt = 0;
|
|
354
|
-
|
|
355
|
-
if (TOKEN_CACHE[cacheKey]) {
|
|
356
|
-
expiresAt = TOKEN_CACHE[cacheKey].expiresAt;
|
|
357
|
-
accessToken = TOKEN_CACHE[cacheKey].accessToken;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (!accessToken || Date.now() >= expiresAt) {
|
|
361
|
-
const privateKey = formatPrivateKey(credentials.privateKey);
|
|
362
|
-
const now = Math.floor(Date.now() / 1000);
|
|
363
|
-
|
|
364
|
-
let jwt;
|
|
365
|
-
if (jwtLib) {
|
|
366
|
-
jwt = jwtLib.sign(
|
|
367
|
-
{
|
|
368
|
-
iss: credentials.email,
|
|
369
|
-
scope: 'https://mail.google.com/',
|
|
370
|
-
aud: 'https://oauth2.googleapis.com/token',
|
|
371
|
-
exp: now + 3600,
|
|
372
|
-
iat: now,
|
|
373
|
-
sub: fromEmail,
|
|
374
|
-
},
|
|
375
|
-
privateKey,
|
|
376
|
-
{
|
|
377
|
-
algorithm: 'RS256',
|
|
378
|
-
header: {
|
|
379
|
-
kid: privateKey,
|
|
380
|
-
typ: 'JWT',
|
|
381
|
-
alg: 'RS256',
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
);
|
|
385
|
-
} else {
|
|
386
|
-
const header = { alg: 'RS256', typ: 'JWT', kid: privateKey };
|
|
387
|
-
const payload = {
|
|
388
|
-
iss: credentials.email,
|
|
389
|
-
scope: 'https://mail.google.com/',
|
|
390
|
-
aud: 'https://oauth2.googleapis.com/token',
|
|
391
|
-
exp: now + 3600,
|
|
392
|
-
iat: now,
|
|
393
|
-
sub: fromEmail,
|
|
394
|
-
};
|
|
395
|
-
const signatureInput = base64UrlEncode(JSON.stringify(header)) + '.' + base64UrlEncode(JSON.stringify(payload));
|
|
396
|
-
const signer = crypto.createSign('RSA-SHA256');
|
|
397
|
-
signer.update(signatureInput);
|
|
398
|
-
const sig = signer.sign(privateKey);
|
|
399
|
-
jwt = signatureInput + '.' + base64urlEscape(sig.toString('base64'));
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const response = await this.helpers.request({
|
|
403
|
-
method: 'POST',
|
|
404
|
-
uri: 'https://oauth2.googleapis.com/token',
|
|
405
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
406
|
-
form: {
|
|
407
|
-
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
408
|
-
assertion: jwt,
|
|
409
|
-
},
|
|
410
|
-
json: true,
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
accessToken = response.access_token;
|
|
414
|
-
TOKEN_CACHE[cacheKey] = {
|
|
415
|
-
accessToken,
|
|
416
|
-
expiresAt: Date.now() + 3500 * 1000,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
407
|
+
const accessToken = await getOrRefreshAccessToken(this, credentials, fromEmail);
|
|
419
408
|
|
|
420
409
|
let attachments = [];
|
|
421
410
|
if (options.attachmentsUi && options.attachmentsUi.attachmentsBinary) {
|
|
@@ -488,10 +477,11 @@ class GmailCustom {
|
|
|
488
477
|
if (lastError) throw lastError;
|
|
489
478
|
|
|
490
479
|
} catch (error) {
|
|
491
|
-
|
|
480
|
+
let continueOnFail = false;
|
|
481
|
+
try { continueOnFail = this.continueOnFail(); } catch (e) {}
|
|
492
482
|
if (continueOnFail) {
|
|
493
483
|
returnData.push({
|
|
494
|
-
json: { error: error.message },
|
|
484
|
+
json: { error: error.message || 'Unknown error' },
|
|
495
485
|
pairedItem: { item: i },
|
|
496
486
|
});
|
|
497
487
|
continue;
|