emailengine-app 2.68.1 → 2.70.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/.github/workflows/deploy.yml +8 -3
- package/.github/workflows/release.yaml +6 -0
- package/CHANGELOG.md +59 -0
- package/Gruntfile.js +3 -1
- package/config/default.toml +2 -0
- package/data/google-crawlers.json +7 -1
- package/getswagger.sh +40 -4
- package/gettext-extract.js +163 -0
- package/lib/account.js +135 -72
- package/lib/api-routes/account-routes.js +684 -106
- package/lib/api-routes/blocklist-routes.js +344 -0
- package/lib/api-routes/chat-routes.js +32 -14
- package/lib/api-routes/delivery-test-routes.js +346 -0
- package/lib/api-routes/export-routes.js +28 -14
- package/lib/api-routes/gateway-routes.js +427 -0
- package/lib/api-routes/license-routes.js +156 -0
- package/lib/api-routes/mailbox-routes.js +344 -0
- package/lib/api-routes/message-routes.js +221 -187
- package/lib/api-routes/oauth2-app-routes.js +697 -0
- package/lib/api-routes/outbox-routes.js +185 -0
- package/lib/api-routes/pubsub-routes.js +102 -0
- package/lib/api-routes/route-helpers.js +58 -0
- package/lib/api-routes/settings-routes.js +357 -0
- package/lib/api-routes/stats-routes.js +111 -0
- package/lib/api-routes/submit-routes.js +461 -0
- package/lib/api-routes/template-routes.js +60 -75
- package/lib/api-routes/token-routes.js +297 -0
- package/lib/api-routes/webhook-route-routes.js +181 -0
- package/lib/autodetect-imap-settings.js +0 -2
- package/lib/consts.js +5 -0
- package/lib/email-client/base-client.js +28 -6
- package/lib/email-client/gmail-client.js +133 -112
- package/lib/email-client/imap/mailbox.js +34 -11
- package/lib/email-client/imap/subconnection.js +20 -13
- package/lib/email-client/imap/sync-operations.js +131 -3
- package/lib/email-client/imap-client.js +152 -75
- package/lib/email-client/notification-handler.js +1 -4
- package/lib/email-client/outlook-client.js +134 -75
- package/lib/export.js +97 -20
- package/lib/feature-flags.js +2 -2
- package/lib/gateway.js +4 -9
- package/lib/get-raw-email.js +5 -5
- package/lib/imapproxy/imap-core/lib/commands/starttls.js +18 -0
- package/lib/imapproxy/imap-core/lib/imap-command.js +6 -1
- package/lib/imapproxy/imap-core/lib/imap-connection.js +106 -24
- package/lib/imapproxy/imap-core/lib/imap-server.js +24 -0
- package/lib/imapproxy/imap-core/lib/imap-stream.js +26 -0
- package/lib/logger.js +24 -21
- package/lib/message-port-stream.js +113 -16
- package/lib/metrics-collector.js +0 -2
- package/lib/oauth2-apps.js +13 -4
- package/lib/outbox.js +24 -40
- package/lib/redis-operations.js +1 -1
- package/lib/reject-worker-calls.js +42 -0
- package/lib/routes-ui.js +37 -8778
- package/lib/schemas.js +429 -84
- package/lib/sentry.js +139 -0
- package/lib/settings.js +9 -3
- package/lib/stream-encrypt.js +1 -1
- package/lib/templates.js +1 -1
- package/lib/tokens.js +5 -3
- package/lib/tools.js +70 -4
- package/lib/ui-routes/account-routes.js +45 -212
- package/lib/ui-routes/admin-config-routes.js +928 -489
- package/lib/ui-routes/admin-entities-routes.js +1 -0
- package/lib/ui-routes/auth-routes.js +1339 -0
- package/lib/ui-routes/dashboard-routes.js +188 -0
- package/lib/ui-routes/document-store-routes.js +800 -0
- package/lib/ui-routes/export-routes.js +217 -0
- package/lib/ui-routes/internals-routes.js +354 -0
- package/lib/ui-routes/network-config-routes.js +759 -0
- package/lib/ui-routes/{oauth-routes.js → oauth-config-routes.js} +369 -91
- package/lib/ui-routes/route-helpers.js +314 -0
- package/lib/ui-routes/smtp-test-routes.js +236 -0
- package/lib/ui-routes/unsubscribe-routes.js +232 -0
- package/lib/webhook-request.js +36 -0
- package/lib/webhooks.js +8 -4
- package/package.json +13 -12
- package/sbom.json +1 -1
- package/server.js +222 -39
- package/static/licenses.html +160 -300
- package/translations/messages.pot +112 -132
- package/update-info.sh +19 -1
- package/views/config/logging.hbs +48 -0
- package/views/dashboard.hbs +7 -26
- package/views/internals/index.hbs +15 -0
- package/views/tokens/index.hbs +9 -0
- package/workers/api.js +200 -4424
- package/workers/documents.js +2 -22
- package/workers/export.js +103 -104
- package/workers/imap-proxy.js +3 -23
- package/workers/imap.js +32 -36
- package/workers/smtp.js +2 -22
- package/workers/submit.js +26 -35
- package/workers/webhooks.js +9 -43
package/workers/submit.js
CHANGED
|
@@ -7,32 +7,12 @@ const config = require('@zone-eu/wild-config');
|
|
|
7
7
|
const logger = require('../lib/logger');
|
|
8
8
|
|
|
9
9
|
const { REDIS_PREFIX } = require('../lib/consts');
|
|
10
|
-
const { getDuration, readEnvValue, threadStats,
|
|
10
|
+
const { getDuration, readEnvValue, threadStats, maybeReloadHttpProxyAgent } = require('../lib/tools');
|
|
11
11
|
const { webhooks: Webhooks } = require('../lib/webhooks');
|
|
12
12
|
const settings = require('../lib/settings');
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
Bugsnag.start({
|
|
17
|
-
apiKey: readEnvValue('BUGSNAG_API_KEY'),
|
|
18
|
-
appVersion: packageData.version,
|
|
19
|
-
logger: {
|
|
20
|
-
debug(...args) {
|
|
21
|
-
logger.debug({ msg: args.shift(), worker: 'submit', source: 'bugsnag', args: args.length ? args : undefined });
|
|
22
|
-
},
|
|
23
|
-
info(...args) {
|
|
24
|
-
logger.debug({ msg: args.shift(), worker: 'submit', source: 'bugsnag', args: args.length ? args : undefined });
|
|
25
|
-
},
|
|
26
|
-
warn(...args) {
|
|
27
|
-
logger.warn({ msg: args.shift(), worker: 'submit', source: 'bugsnag', args: args.length ? args : undefined });
|
|
28
|
-
},
|
|
29
|
-
error(...args) {
|
|
30
|
-
logger.error({ msg: args.shift(), worker: 'submit', source: 'bugsnag', args: args.length ? args : undefined });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
logger.notifyError = Bugsnag.notify.bind(Bugsnag);
|
|
35
|
-
}
|
|
14
|
+
const { initSentry } = require('../lib/sentry');
|
|
15
|
+
initSentry('submit');
|
|
36
16
|
|
|
37
17
|
const util = require('util');
|
|
38
18
|
const { redis, queueConf, submitQueue } = require('../lib/db');
|
|
@@ -222,13 +202,15 @@ const submitWorker = new Worker(
|
|
|
222
202
|
}
|
|
223
203
|
|
|
224
204
|
let backoffDelay = Number(job.opts.backoff && job.opts.backoff.delay) || 0;
|
|
225
|
-
|
|
205
|
+
// job.attemptsMade is not yet incremented for the ongoing attempt, so the
|
|
206
|
+
// next retry (if this attempt fails) is delayed by 2^attemptsMade * base
|
|
207
|
+
let nextAttempt = job.attemptsMade + 1 < job.opts.attempts ? Math.round(job.processedOn + Math.pow(2, job.attemptsMade) * backoffDelay) : false;
|
|
226
208
|
|
|
227
209
|
queueEntry.job = {
|
|
228
210
|
id: job.id,
|
|
229
211
|
attemptsMade: job.attemptsMade,
|
|
230
212
|
attempts: job.opts.attempts,
|
|
231
|
-
nextAttempt: new Date(nextAttempt).toISOString()
|
|
213
|
+
nextAttempt: nextAttempt ? new Date(nextAttempt).toISOString() : false
|
|
232
214
|
};
|
|
233
215
|
|
|
234
216
|
let res = await accountObject.submitMessage(queueEntry);
|
|
@@ -409,12 +391,24 @@ submitWorker.on('failed', async job => {
|
|
|
409
391
|
logger.error({ msg: 'Failed to remove queue entry', account: job.data.account, queueId: job.data.queueId, messageId: job.data.messageId, err });
|
|
410
392
|
}
|
|
411
393
|
// report as failed
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
394
|
+
try {
|
|
395
|
+
await notify(job.data.account, EMAIL_FAILED_NOTIFY, {
|
|
396
|
+
messageId: job.data.messageId,
|
|
397
|
+
queueId: job.data.queueId,
|
|
398
|
+
error: job.stacktrace && job.stacktrace[0] && job.stacktrace[0].split('\n').shift(),
|
|
399
|
+
networkRouting: job.progress?.networkRouting
|
|
400
|
+
});
|
|
401
|
+
} catch (notifyErr) {
|
|
402
|
+
// A failed webhook notification must not bubble out of this BullMQ
|
|
403
|
+
// event listener as an unhandled rejection and take down the worker.
|
|
404
|
+
logger.error({
|
|
405
|
+
msg: 'Failed to deliver submission failure notification',
|
|
406
|
+
account: job.data.account,
|
|
407
|
+
queueId: job.data.queueId,
|
|
408
|
+
messageId: job.data.messageId,
|
|
409
|
+
err: notifyErr
|
|
410
|
+
});
|
|
411
|
+
}
|
|
418
412
|
}
|
|
419
413
|
}
|
|
420
414
|
|
|
@@ -497,10 +491,7 @@ parentPort.on('message', message => {
|
|
|
497
491
|
}
|
|
498
492
|
|
|
499
493
|
if (message && message.cmd === 'settings') {
|
|
500
|
-
|
|
501
|
-
if ('httpProxyEnabled' in d || 'httpProxyUrl' in d) {
|
|
502
|
-
reloadHttpProxyAgent().catch(err => logger.error({ msg: 'Failed to reload HTTP proxy agent', err }));
|
|
503
|
-
}
|
|
494
|
+
maybeReloadHttpProxyAgent(message.data);
|
|
504
495
|
}
|
|
505
496
|
});
|
|
506
497
|
|
package/workers/webhooks.js
CHANGED
|
@@ -10,30 +10,11 @@ const { webhooks: Webhooks } = require('../lib/webhooks');
|
|
|
10
10
|
|
|
11
11
|
const { GooglePubSub } = require('../lib/oauth/pubsub/google');
|
|
12
12
|
|
|
13
|
-
const { readEnvValue, threadStats, getDuration, httpAgent, getServiceSecret,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
apiKey: readEnvValue('BUGSNAG_API_KEY'),
|
|
19
|
-
appVersion: packageData.version,
|
|
20
|
-
logger: {
|
|
21
|
-
debug(...args) {
|
|
22
|
-
logger.debug({ msg: args.shift(), worker: 'webhooks', source: 'bugsnag', args: args.length ? args : undefined });
|
|
23
|
-
},
|
|
24
|
-
info(...args) {
|
|
25
|
-
logger.debug({ msg: args.shift(), worker: 'webhooks', source: 'bugsnag', args: args.length ? args : undefined });
|
|
26
|
-
},
|
|
27
|
-
warn(...args) {
|
|
28
|
-
logger.warn({ msg: args.shift(), worker: 'webhooks', source: 'bugsnag', args: args.length ? args : undefined });
|
|
29
|
-
},
|
|
30
|
-
error(...args) {
|
|
31
|
-
logger.error({ msg: args.shift(), worker: 'webhooks', source: 'bugsnag', args: args.length ? args : undefined });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
logger.notifyError = Bugsnag.notify.bind(Bugsnag);
|
|
36
|
-
}
|
|
13
|
+
const { readEnvValue, threadStats, getDuration, httpAgent, getServiceSecret, maybeReloadHttpProxyAgent } = require('../lib/tools');
|
|
14
|
+
const { sendWebhookRequest } = require('../lib/webhook-request');
|
|
15
|
+
|
|
16
|
+
const { initSentry } = require('../lib/sentry');
|
|
17
|
+
initSentry('webhooks');
|
|
37
18
|
|
|
38
19
|
const { redis, queueConf } = require('../lib/db');
|
|
39
20
|
const { Worker } = require('bullmq');
|
|
@@ -199,10 +180,7 @@ parentPort.on('message', message => {
|
|
|
199
180
|
}
|
|
200
181
|
|
|
201
182
|
if (message && message.cmd === 'settings') {
|
|
202
|
-
|
|
203
|
-
if ('httpProxyEnabled' in d || 'httpProxyUrl' in d) {
|
|
204
|
-
reloadHttpProxyAgent().catch(err => logger.error({ msg: 'Failed to reload HTTP proxy agent', err }));
|
|
205
|
-
}
|
|
183
|
+
maybeReloadHttpProxyAgent(message.data);
|
|
206
184
|
}
|
|
207
185
|
});
|
|
208
186
|
|
|
@@ -424,9 +402,9 @@ const notifyWorker = new Worker(
|
|
|
424
402
|
headers['X-EE-Wh-Signature'] = hmac.digest('base64url');
|
|
425
403
|
|
|
426
404
|
try {
|
|
427
|
-
let
|
|
405
|
+
let status;
|
|
428
406
|
try {
|
|
429
|
-
|
|
407
|
+
status = await sendWebhookRequest(fetchCmd, parsed.toString(), {
|
|
430
408
|
method: 'post',
|
|
431
409
|
body,
|
|
432
410
|
headers,
|
|
@@ -438,18 +416,6 @@ const notifyWorker = new Worker(
|
|
|
438
416
|
throw err.cause || err;
|
|
439
417
|
}
|
|
440
418
|
|
|
441
|
-
if (!res.ok) {
|
|
442
|
-
// Drain response body to release connection back to pool
|
|
443
|
-
try {
|
|
444
|
-
await res.text();
|
|
445
|
-
} catch {
|
|
446
|
-
// ignore drain errors
|
|
447
|
-
}
|
|
448
|
-
let err = new Error(res.statusText || `Invalid response: ${res.status} ${res.statusText}`);
|
|
449
|
-
err.statusCode = res.status;
|
|
450
|
-
throw err;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
419
|
logger.trace({
|
|
454
420
|
msg: 'Webhook posted',
|
|
455
421
|
action: 'webhook',
|
|
@@ -460,7 +426,7 @@ const notifyWorker = new Worker(
|
|
|
460
426
|
requestBodySize: body.length,
|
|
461
427
|
accountWebhooks: !!accountWebhooks,
|
|
462
428
|
event: job.name,
|
|
463
|
-
status
|
|
429
|
+
status,
|
|
464
430
|
account: job.data.account,
|
|
465
431
|
route: customRoute && customRoute.id
|
|
466
432
|
});
|