emailengine-app 2.61.5 → 2.62.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.
- package/CHANGELOG.md +78 -0
- package/data/google-crawlers.json +1 -1
- package/lib/account.js +20 -7
- package/lib/api-routes/account-routes.js +28 -5
- package/lib/api-routes/chat-routes.js +1 -1
- package/lib/api-routes/export-routes.js +316 -0
- package/lib/api-routes/message-routes.js +28 -23
- package/lib/api-routes/template-routes.js +28 -7
- package/lib/arf-detect.js +1 -1
- package/lib/consts.js +16 -0
- package/lib/db.js +3 -0
- package/lib/email-client/base-client.js +6 -4
- package/lib/email-client/gmail-client.js +204 -33
- package/lib/email-client/imap/mailbox.js +99 -8
- package/lib/email-client/imap/subconnection.js +5 -5
- package/lib/email-client/imap-client.js +76 -16
- package/lib/email-client/message-builder.js +3 -1
- package/lib/email-client/notification-handler.js +12 -9
- package/lib/email-client/outlook-client.js +362 -69
- package/lib/email-client/smtp-pool-manager.js +1 -1
- package/lib/export.js +528 -0
- package/lib/oauth/gmail.js +21 -13
- package/lib/oauth/mail-ru.js +23 -10
- package/lib/oauth/outlook.js +26 -16
- package/lib/oauth/pubsub/google.js +5 -0
- package/lib/routes-ui.js +235 -1
- package/lib/schemas.js +260 -80
- package/lib/stream-encrypt.js +263 -0
- package/lib/tools.js +30 -4
- package/lib/ui-routes/account-routes.js +23 -0
- package/lib/ui-routes/admin-config-routes.js +11 -4
- package/lib/ui-routes/admin-entities-routes.js +18 -0
- package/lib/webhooks.js +16 -20
- package/package.json +16 -16
- package/sbom.json +1 -1
- package/server.js +41 -5
- package/static/js/ace/ace.js +1 -1
- package/static/js/ace/ext-language_tools.js +1 -1
- package/static/licenses.html +52 -62
- package/translations/de.mo +0 -0
- package/translations/de.po +63 -36
- package/translations/en.mo +0 -0
- package/translations/en.po +64 -37
- package/translations/et.mo +0 -0
- package/translations/et.po +63 -36
- package/translations/fr.mo +0 -0
- package/translations/fr.po +63 -36
- package/translations/ja.mo +0 -0
- package/translations/ja.po +63 -36
- package/translations/messages.pot +80 -47
- package/translations/nl.mo +0 -0
- package/translations/nl.po +63 -36
- package/translations/pl.mo +0 -0
- package/translations/pl.po +63 -36
- package/views/accounts/account.hbs +375 -2
- package/views/config/service.hbs +35 -0
- package/workers/api.js +123 -44
- package/workers/documents.js +1 -0
- package/workers/export.js +926 -0
- package/workers/imap.js +29 -0
- package/workers/submit.js +25 -5
- package/workers/webhooks.js +11 -2
package/workers/imap.js
CHANGED
|
@@ -452,6 +452,34 @@ class ConnectionHandler {
|
|
|
452
452
|
return await accountData.connection.getMessage(message.message, message.options);
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
async getMessages(message) {
|
|
456
|
+
if (!this.accounts.has(message.account)) {
|
|
457
|
+
throw NO_ACTIVE_HANDLER_RESP_ERR;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
let accountData = this.accounts.get(message.account);
|
|
461
|
+
if (!accountData.connection) {
|
|
462
|
+
throw NO_ACTIVE_HANDLER_RESP_ERR;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Use batch method if available (Gmail/Outlook API clients)
|
|
466
|
+
if (typeof accountData.connection.getMessages === 'function') {
|
|
467
|
+
return await accountData.connection.getMessages(message.messageIds, message.options);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Fallback to sequential fetching for IMAP
|
|
471
|
+
const results = [];
|
|
472
|
+
for (const messageId of message.messageIds) {
|
|
473
|
+
try {
|
|
474
|
+
const msg = await accountData.connection.getMessage(messageId, message.options);
|
|
475
|
+
results.push({ messageId, data: msg, error: null });
|
|
476
|
+
} catch (err) {
|
|
477
|
+
results.push({ messageId, data: null, error: { message: err.message, code: err.code } });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return results;
|
|
481
|
+
}
|
|
482
|
+
|
|
455
483
|
async updateMessage(message) {
|
|
456
484
|
if (!this.accounts.has(message.account)) {
|
|
457
485
|
throw NO_ACTIVE_HANDLER_RESP_ERR;
|
|
@@ -841,6 +869,7 @@ class ConnectionHandler {
|
|
|
841
869
|
case 'listMessages':
|
|
842
870
|
case 'getText':
|
|
843
871
|
case 'getMessage':
|
|
872
|
+
case 'getMessages':
|
|
844
873
|
case 'updateMessage':
|
|
845
874
|
case 'updateMessages':
|
|
846
875
|
case 'listMailboxes':
|
package/workers/submit.js
CHANGED
|
@@ -62,6 +62,16 @@ const SUBMIT_QC = (readEnvValue('EENGINE_SUBMIT_QC') && Number(readEnvValue('EEN
|
|
|
62
62
|
|
|
63
63
|
const SUBMIT_DELAY = getDuration(readEnvValue('EENGINE_SUBMIT_DELAY') || config.submitDelay) || null;
|
|
64
64
|
|
|
65
|
+
const NON_RETRYABLE_CODES = new Set([
|
|
66
|
+
'EAUTH', // authentication failed
|
|
67
|
+
'ENOAUTH', // no credentials provided
|
|
68
|
+
'EOAUTH2', // OAuth2 token failure
|
|
69
|
+
'ETLS', // TLS handshake failed
|
|
70
|
+
'EENVELOPE', // invalid sender/recipients
|
|
71
|
+
'EMESSAGE', // message content error
|
|
72
|
+
'EPROTOCOL' // SMTP protocol mismatch
|
|
73
|
+
]);
|
|
74
|
+
|
|
65
75
|
let callQueue = new Map();
|
|
66
76
|
let mids = 0;
|
|
67
77
|
|
|
@@ -295,9 +305,11 @@ const submitWorker = new Worker(
|
|
|
295
305
|
// ignore
|
|
296
306
|
}
|
|
297
307
|
|
|
298
|
-
|
|
308
|
+
const isPermanentSmtp = err.statusCode >= 500 && err.statusCode !== 503;
|
|
309
|
+
const isPermanentCode = NON_RETRYABLE_CODES.has(err.code);
|
|
310
|
+
if ((isPermanentSmtp || isPermanentCode) && job.attemptsMade < job.opts.attempts) {
|
|
299
311
|
try {
|
|
300
|
-
// do not retry after 5xx error
|
|
312
|
+
// do not retry after 5xx error (except 503 which is transient)
|
|
301
313
|
await job.discard();
|
|
302
314
|
logger.info({
|
|
303
315
|
msg: 'Job discarded',
|
|
@@ -305,9 +317,6 @@ const submitWorker = new Worker(
|
|
|
305
317
|
queueId: job.data.queueId
|
|
306
318
|
});
|
|
307
319
|
} catch (E) {
|
|
308
|
-
// ignore
|
|
309
|
-
logger.error({ msg: 'Failed to discard job', account: queueEntry.account, queueId: job.data.queueId, err: E });
|
|
310
|
-
|
|
311
320
|
logger.error({
|
|
312
321
|
msg: 'Failed to discard job',
|
|
313
322
|
action: 'submit',
|
|
@@ -329,6 +338,17 @@ const submitWorker = new Worker(
|
|
|
329
338
|
{
|
|
330
339
|
concurrency: SUBMIT_QC,
|
|
331
340
|
|
|
341
|
+
// Lock duration must exceed SMTP socket timeout (2 min) to prevent
|
|
342
|
+
// jobs from being marked stalled during normal email delivery
|
|
343
|
+
lockDuration: 3 * 60 * 1000, // 3 minutes
|
|
344
|
+
|
|
345
|
+
// Check for stalled jobs every 60 seconds
|
|
346
|
+
stalledInterval: 60 * 1000,
|
|
347
|
+
|
|
348
|
+
// Allow jobs to recover from stalled state up to 3 times before failing
|
|
349
|
+
// This handles transient Redis latency or connection issues
|
|
350
|
+
maxStalledCount: 3,
|
|
351
|
+
|
|
332
352
|
limiter: SUBMIT_DELAY
|
|
333
353
|
? {
|
|
334
354
|
max: 1,
|
package/workers/webhooks.js
CHANGED
|
@@ -293,7 +293,7 @@ const notifyWorker = new Worker(
|
|
|
293
293
|
{
|
|
294
294
|
let filteredSubData = {};
|
|
295
295
|
let isPartial = false;
|
|
296
|
-
for (let dataKey of Object.keys(job.data.data)) {
|
|
296
|
+
for (let dataKey of Object.keys(job.data.data || {})) {
|
|
297
297
|
switch (dataKey) {
|
|
298
298
|
case 'id':
|
|
299
299
|
case 'uid':
|
|
@@ -546,7 +546,16 @@ route: customRoute && customRoute.id,
|
|
|
546
546
|
},
|
|
547
547
|
Object.assign(
|
|
548
548
|
{
|
|
549
|
-
concurrency: Number(NOTIFY_QC) || 1
|
|
549
|
+
concurrency: Number(NOTIFY_QC) || 1,
|
|
550
|
+
|
|
551
|
+
// Webhook HTTP requests have 90s timeout, lock should exceed this
|
|
552
|
+
lockDuration: 3 * 60 * 1000, // 3 minutes
|
|
553
|
+
|
|
554
|
+
// Check for stalled jobs every 60 seconds
|
|
555
|
+
stalledInterval: 60 * 1000,
|
|
556
|
+
|
|
557
|
+
// Allow jobs to recover from stalled state up to 3 times
|
|
558
|
+
maxStalledCount: 3
|
|
550
559
|
},
|
|
551
560
|
queueConf || {}
|
|
552
561
|
)
|