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.
Files changed (62) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/data/google-crawlers.json +1 -1
  3. package/lib/account.js +20 -7
  4. package/lib/api-routes/account-routes.js +28 -5
  5. package/lib/api-routes/chat-routes.js +1 -1
  6. package/lib/api-routes/export-routes.js +316 -0
  7. package/lib/api-routes/message-routes.js +28 -23
  8. package/lib/api-routes/template-routes.js +28 -7
  9. package/lib/arf-detect.js +1 -1
  10. package/lib/consts.js +16 -0
  11. package/lib/db.js +3 -0
  12. package/lib/email-client/base-client.js +6 -4
  13. package/lib/email-client/gmail-client.js +204 -33
  14. package/lib/email-client/imap/mailbox.js +99 -8
  15. package/lib/email-client/imap/subconnection.js +5 -5
  16. package/lib/email-client/imap-client.js +76 -16
  17. package/lib/email-client/message-builder.js +3 -1
  18. package/lib/email-client/notification-handler.js +12 -9
  19. package/lib/email-client/outlook-client.js +362 -69
  20. package/lib/email-client/smtp-pool-manager.js +1 -1
  21. package/lib/export.js +528 -0
  22. package/lib/oauth/gmail.js +21 -13
  23. package/lib/oauth/mail-ru.js +23 -10
  24. package/lib/oauth/outlook.js +26 -16
  25. package/lib/oauth/pubsub/google.js +5 -0
  26. package/lib/routes-ui.js +235 -1
  27. package/lib/schemas.js +260 -80
  28. package/lib/stream-encrypt.js +263 -0
  29. package/lib/tools.js +30 -4
  30. package/lib/ui-routes/account-routes.js +23 -0
  31. package/lib/ui-routes/admin-config-routes.js +11 -4
  32. package/lib/ui-routes/admin-entities-routes.js +18 -0
  33. package/lib/webhooks.js +16 -20
  34. package/package.json +16 -16
  35. package/sbom.json +1 -1
  36. package/server.js +41 -5
  37. package/static/js/ace/ace.js +1 -1
  38. package/static/js/ace/ext-language_tools.js +1 -1
  39. package/static/licenses.html +52 -62
  40. package/translations/de.mo +0 -0
  41. package/translations/de.po +63 -36
  42. package/translations/en.mo +0 -0
  43. package/translations/en.po +64 -37
  44. package/translations/et.mo +0 -0
  45. package/translations/et.po +63 -36
  46. package/translations/fr.mo +0 -0
  47. package/translations/fr.po +63 -36
  48. package/translations/ja.mo +0 -0
  49. package/translations/ja.po +63 -36
  50. package/translations/messages.pot +80 -47
  51. package/translations/nl.mo +0 -0
  52. package/translations/nl.po +63 -36
  53. package/translations/pl.mo +0 -0
  54. package/translations/pl.po +63 -36
  55. package/views/accounts/account.hbs +375 -2
  56. package/views/config/service.hbs +35 -0
  57. package/workers/api.js +123 -44
  58. package/workers/documents.js +1 -0
  59. package/workers/export.js +926 -0
  60. package/workers/imap.js +29 -0
  61. package/workers/submit.js +25 -5
  62. package/workers/webhooks.js +11 -2
package/server.js CHANGED
@@ -131,7 +131,7 @@ if (readEnvValue('BUGSNAG_API_KEY')) {
131
131
 
132
132
  // Import additional dependencies
133
133
  const pathlib = require('path');
134
- const { redis, queueConf } = require('./lib/db');
134
+ const { redis, queueConf, notifyQueue, submitQueue, documentsQueue, exportQueue } = require('./lib/db');
135
135
  const promClient = require('prom-client');
136
136
  const fs = require('fs').promises;
137
137
  const crypto = require('crypto');
@@ -302,6 +302,7 @@ const THREAD_NAMES = {
302
302
  webhooks: 'Webhook worker',
303
303
  api: 'HTTP and API server',
304
304
  submit: 'Email sending worker',
305
+ export: 'Export worker',
305
306
  documents: 'Document store indexing worker',
306
307
  imapProxy: 'IMAP proxy server',
307
308
  smtp: 'SMTP proxy server'
@@ -314,7 +315,8 @@ const THREAD_NAMES = {
314
315
  const THREAD_CONFIG_VALUES = {
315
316
  imap: { key: 'EENGINE_WORKERS', value: config.workers.imap },
316
317
  submit: { key: 'EENGINE_WORKERS_SUBMIT', value: config.workers.submit },
317
- webhooks: { key: 'EENGINE_WORKERS_WEBHOOKS', value: config.workers.webhooks }
318
+ webhooks: { key: 'EENGINE_WORKERS_WEBHOOKS', value: config.workers.webhooks },
319
+ export: { key: 'EENGINE_WORKERS_EXPORT', value: config.workers.export || 1 }
318
320
  };
319
321
 
320
322
  // Queue event handlers for different job queues
@@ -2618,10 +2620,13 @@ async function onCommand(worker, message) {
2618
2620
  break;
2619
2621
 
2620
2622
  // IMAP operations - forward to assigned worker
2623
+ case 'submitMessage':
2624
+ case 'queueMessage':
2621
2625
  case 'listMessages':
2622
2626
  case 'getRawMessage':
2623
2627
  case 'getText':
2624
2628
  case 'getMessage':
2629
+ case 'getMessages':
2625
2630
  case 'updateMessage':
2626
2631
  case 'updateMessages':
2627
2632
  case 'listMailboxes':
@@ -2633,8 +2638,6 @@ async function onCommand(worker, message) {
2633
2638
  case 'createMailbox':
2634
2639
  case 'modifyMailbox':
2635
2640
  case 'deleteMailbox':
2636
- case 'submitMessage':
2637
- case 'queueMessage':
2638
2641
  case 'uploadMessage':
2639
2642
  case 'getAttachment':
2640
2643
  case 'listSignatures': {
@@ -2649,7 +2652,6 @@ async function onCommand(worker, message) {
2649
2652
  if (['getRawMessage', 'getAttachment'].includes(message.cmd) && message.port) {
2650
2653
  transferList.push(message.port);
2651
2654
  }
2652
-
2653
2655
  if (['submitMessage', 'queueMessage'].includes(message.cmd) && typeof message.raw === 'object') {
2654
2656
  transferList.push(message.raw);
2655
2657
  }
@@ -2779,6 +2781,10 @@ const closeQueues = cb => {
2779
2781
  proms.push(queueEvents.documents.close());
2780
2782
  }
2781
2783
 
2784
+ if (queueEvents.export) {
2785
+ proms.push(queueEvents.export.close());
2786
+ }
2787
+
2782
2788
  if (!proms.length) {
2783
2789
  return setImmediate(() => cb());
2784
2790
  }
@@ -3105,6 +3111,11 @@ const startApplication = async () => {
3105
3111
  await spawnWorker('submit');
3106
3112
  }
3107
3113
 
3114
+ // Start export workers
3115
+ for (let i = 0; i < (config.workers.export || 1); i++) {
3116
+ await spawnWorker('export');
3117
+ }
3118
+
3108
3119
  // Start document processing worker
3109
3120
  await spawnWorker('documents');
3110
3121
 
@@ -3187,6 +3198,31 @@ startApplication()
3187
3198
  queueEvents.notify = new QueueEvents('notify', Object.assign({}, queueConf));
3188
3199
  queueEvents.submit = new QueueEvents('submit', Object.assign({}, queueConf));
3189
3200
  queueEvents.documents = new QueueEvents('documents', Object.assign({}, queueConf));
3201
+ queueEvents.export = new QueueEvents('export', Object.assign({}, queueConf));
3202
+
3203
+ // Periodic queue cleanup (every 6 hours)
3204
+ const QUEUE_CLEANUP_INTERVAL = 6 * 60 * 60 * 1000;
3205
+
3206
+ async function cleanupQueues() {
3207
+ const queues = [notifyQueue, submitQueue, documentsQueue, exportQueue];
3208
+ for (const queue of queues) {
3209
+ try {
3210
+ // Clean completed jobs older than 24 hours
3211
+ await queue.clean(24 * 60 * 60 * 1000, 10000, 'completed');
3212
+ // Clean failed jobs older than 7 days
3213
+ await queue.clean(7 * 24 * 60 * 60 * 1000, 10000, 'failed');
3214
+ logger.trace({ msg: 'Queue cleanup completed', queue: queue.name });
3215
+ } catch (err) {
3216
+ logger.error({ msg: 'Queue cleanup failed', queue: queue.name, err });
3217
+ }
3218
+ }
3219
+ }
3220
+
3221
+ const queueCleanupTimer = setInterval(cleanupQueues, QUEUE_CLEANUP_INTERVAL);
3222
+ queueCleanupTimer.unref();
3223
+
3224
+ // Initial cleanup 5 minutes after startup
3225
+ setTimeout(cleanupQueues, 5 * 60 * 1000).unref();
3190
3226
  })
3191
3227
  .catch(err => {
3192
3228
  logger.fatal({ msg: 'Application startup failed', err });