emailengine-app 2.61.0 → 2.61.2
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 +16 -0
- package/data/google-crawlers.json +1 -1
- package/lib/account/account-state.js +248 -0
- package/lib/account.js +17 -178
- package/lib/api-routes/account-routes.js +1006 -0
- package/lib/api-routes/message-routes.js +1377 -0
- package/lib/consts.js +12 -2
- package/lib/email-client/base-client.js +282 -771
- package/lib/email-client/gmail/gmail-api.js +243 -0
- package/lib/email-client/gmail-client.js +145 -53
- package/lib/email-client/imap/mailbox.js +24 -698
- package/lib/email-client/imap/sync-operations.js +812 -0
- package/lib/email-client/imap-client.js +3 -1
- package/lib/email-client/message-builder.js +566 -0
- package/lib/email-client/notification-handler.js +314 -0
- package/lib/email-client/outlook/graph-api.js +326 -0
- package/lib/email-client/outlook-client.js +159 -113
- package/lib/email-client/smtp-pool-manager.js +196 -0
- package/lib/imapproxy/imap-server.js +3 -12
- package/lib/oauth/gmail.js +4 -4
- package/lib/oauth/mail-ru.js +30 -5
- package/lib/oauth/outlook.js +57 -3
- package/lib/oauth/pubsub/google.js +30 -11
- package/lib/oauth/scope-checker.js +202 -0
- package/lib/oauth2-apps.js +8 -4
- package/lib/redis-operations.js +484 -0
- package/lib/routes-ui.js +283 -2582
- package/lib/tools.js +5 -196
- package/lib/ui-routes/account-routes.js +1931 -0
- package/lib/ui-routes/admin-config-routes.js +1233 -0
- package/lib/ui-routes/admin-entities-routes.js +2367 -0
- package/lib/ui-routes/oauth-routes.js +992 -0
- package/lib/utils/network.js +237 -0
- package/package.json +12 -12
- package/sbom.json +1 -1
- package/static/js/app.js +5 -5
- package/static/licenses.html +91 -21
- package/translations/de.mo +0 -0
- package/translations/de.po +85 -82
- package/translations/en.mo +0 -0
- package/translations/en.po +63 -71
- package/translations/et.mo +0 -0
- package/translations/et.po +84 -82
- package/translations/fr.mo +0 -0
- package/translations/fr.po +85 -82
- package/translations/ja.mo +0 -0
- package/translations/ja.po +84 -82
- package/translations/messages.pot +67 -80
- package/translations/nl.mo +0 -0
- package/translations/nl.po +86 -82
- package/translations/pl.mo +0 -0
- package/translations/pl.po +84 -82
- package/views/account/security.hbs +4 -4
- package/views/accounts/account.hbs +13 -13
- package/views/accounts/register/imap-server.hbs +12 -12
- package/views/config/document-store/pre-processing/index.hbs +4 -2
- package/views/config/oauth/app.hbs +6 -7
- package/views/config/oauth/index.hbs +2 -2
- package/views/config/service.hbs +3 -4
- package/views/dashboard.hbs +5 -7
- package/views/error.hbs +22 -7
- package/views/gateways/gateway.hbs +2 -2
- package/views/partials/add_account_modal.hbs +7 -10
- package/views/partials/document_store_header.hbs +1 -1
- package/views/partials/editor_scope_info.hbs +0 -1
- package/views/partials/oauth_config_header.hbs +1 -1
- package/views/partials/side_menu.hbs +3 -3
- package/views/partials/webhook_form.hbs +2 -2
- package/views/templates/index.hbs +1 -1
- package/views/templates/template.hbs +8 -8
- package/views/tokens/index.hbs +6 -6
- package/views/tokens/new.hbs +1 -1
- package/views/webhooks/index.hbs +4 -4
- package/views/webhooks/webhook.hbs +7 -7
- package/workers/api.js +148 -2436
- package/workers/smtp.js +2 -1
- package/workers/webhooks.js +6 -0
- package/lib/imapproxy/imap-core/test/client.js +0 -46
- package/lib/imapproxy/imap-core/test/fixtures/append.eml +0 -1196
- package/lib/imapproxy/imap-core/test/fixtures/chunks.js +0 -44
- package/lib/imapproxy/imap-core/test/fixtures/fix1.eml +0 -6
- package/lib/imapproxy/imap-core/test/fixtures/fix2.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/fix3.eml +0 -32
- package/lib/imapproxy/imap-core/test/fixtures/fix4.eml +0 -6
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.js +0 -2740
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.json +0 -1411
- package/lib/imapproxy/imap-core/test/fixtures/mimetree.js +0 -85
- package/lib/imapproxy/imap-core/test/fixtures/nodemailer.eml +0 -582
- package/lib/imapproxy/imap-core/test/fixtures/ryan_finnie_mime_torture.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/simple.eml +0 -42
- package/lib/imapproxy/imap-core/test/fixtures/simple.json +0 -164
- package/lib/imapproxy/imap-core/test/imap-compile-stream-test.js +0 -671
- package/lib/imapproxy/imap-core/test/imap-compiler-test.js +0 -272
- package/lib/imapproxy/imap-core/test/imap-indexer-test.js +0 -236
- package/lib/imapproxy/imap-core/test/imap-parser-test.js +0 -922
- package/lib/imapproxy/imap-core/test/memory-notifier.js +0 -129
- package/lib/imapproxy/imap-core/test/prepare.sh +0 -74
- package/lib/imapproxy/imap-core/test/protocol-test.js +0 -1756
- package/lib/imapproxy/imap-core/test/search-test.js +0 -1356
- package/lib/imapproxy/imap-core/test/test-client.js +0 -152
- package/lib/imapproxy/imap-core/test/test-server.js +0 -623
- package/lib/imapproxy/imap-core/test/tools-test.js +0 -22
- package/test/api-test.js +0 -899
- package/test/autoreply-test.js +0 -327
- package/test/bounce-test.js +0 -151
- package/test/complaint-test.js +0 -256
- package/test/fixtures/autoreply/LICENSE +0 -27
- package/test/fixtures/autoreply/rfc3834-01.eml +0 -23
- package/test/fixtures/autoreply/rfc3834-02.eml +0 -24
- package/test/fixtures/autoreply/rfc3834-03.eml +0 -26
- package/test/fixtures/autoreply/rfc3834-04.eml +0 -48
- package/test/fixtures/autoreply/rfc3834-05.eml +0 -19
- package/test/fixtures/autoreply/rfc3834-06.eml +0 -59
- package/test/fixtures/bounces/163.eml +0 -2521
- package/test/fixtures/bounces/fastmail.eml +0 -242
- package/test/fixtures/bounces/gmail.eml +0 -252
- package/test/fixtures/bounces/hotmail.eml +0 -655
- package/test/fixtures/bounces/mailru.eml +0 -121
- package/test/fixtures/bounces/outlook.eml +0 -1107
- package/test/fixtures/bounces/postfix.eml +0 -101
- package/test/fixtures/bounces/rambler.eml +0 -116
- package/test/fixtures/bounces/workmail.eml +0 -142
- package/test/fixtures/bounces/yahoo.eml +0 -139
- package/test/fixtures/bounces/zoho.eml +0 -83
- package/test/fixtures/bounces/zonemta.eml +0 -100
- package/test/fixtures/complaints/LICENSE +0 -27
- package/test/fixtures/complaints/amazonses.eml +0 -72
- package/test/fixtures/complaints/dmarc.eml +0 -59
- package/test/fixtures/complaints/hotmail.eml +0 -49
- package/test/fixtures/complaints/optout.eml +0 -40
- package/test/fixtures/complaints/standard-arf.eml +0 -68
- package/test/fixtures/complaints/yahoo.eml +0 -68
- package/test/oauth2-apps-test.js +0 -301
- package/test/sendonly-test.js +0 -160
- package/test/test-config.js +0 -34
- package/test/webhooks-server.js +0 -39
package/test/autoreply-test.js
DELETED
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Test fixtures in fixtures/autoreply/ are from:
|
|
4
|
-
// https://github.com/sisimai/set-of-emails/
|
|
5
|
-
// Licensed under BSD 2-Clause License, Copyright (C) 2014, azumakuniyuki
|
|
6
|
-
|
|
7
|
-
const test = require('node:test');
|
|
8
|
-
const assert = require('node:assert').strict;
|
|
9
|
-
|
|
10
|
-
const { simpleParser } = require('mailparser');
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const Path = require('path');
|
|
13
|
-
|
|
14
|
-
const path = fname => Path.join(__dirname, 'fixtures', 'autoreply', fname);
|
|
15
|
-
|
|
16
|
-
// Replicate isAutoreply logic from base-client.js for testing
|
|
17
|
-
function isAutoreply(messageData) {
|
|
18
|
-
// Check subject patterns - these are strong autoreply indicators
|
|
19
|
-
// Note: "Automatic reply:" and "Auto reply:" (with space) are common variants
|
|
20
|
-
// "Out of the Office" is also valid (with "the")
|
|
21
|
-
if (/^(auto(matic)?\s*(reply|response)|Out of(?: the)? Office|OOF:|OOO:)/i.test(messageData.subject)) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Weaker subject patterns require inReplyTo as confirmation
|
|
26
|
-
if (/^auto:/i.test(messageData.subject) && messageData.inReplyTo) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!messageData.headers) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Check Precedence header
|
|
35
|
-
if (messageData.headers.precedence && messageData.headers.precedence.some(e => /auto[_-]?reply/.test(e))) {
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Check Auto-Submitted header (RFC 3834)
|
|
40
|
-
if (messageData.headers['auto-submitted'] && messageData.headers['auto-submitted'].some(e => /auto[_-]?replied/.test(e))) {
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Check X-Auto-Response-Suppress header (Microsoft Exchange)
|
|
45
|
-
// Values like "All", "OOF", "AutoReply" indicate this is an autoreply
|
|
46
|
-
if (messageData.headers['x-auto-response-suppress'] && messageData.headers['x-auto-response-suppress'].length) {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Check various vendor-specific headers
|
|
51
|
-
for (let headerKey of ['x-autoresponder', 'x-autorespond', 'x-autoreply']) {
|
|
52
|
-
if (messageData.headers[headerKey] && messageData.headers[headerKey].length) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Convert parsed email headers to the format expected by isAutoreply
|
|
61
|
-
function convertHeaders(parsed) {
|
|
62
|
-
const headers = {};
|
|
63
|
-
if (parsed.headers) {
|
|
64
|
-
for (let [key, value] of parsed.headers) {
|
|
65
|
-
let normalizedKey = key.toLowerCase();
|
|
66
|
-
if (!headers[normalizedKey]) {
|
|
67
|
-
headers[normalizedKey] = [];
|
|
68
|
-
}
|
|
69
|
-
headers[normalizedKey].push(value);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return headers;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Helper to parse email and prepare messageData for isAutoreply
|
|
76
|
-
async function parseForAutoreply(filePath) {
|
|
77
|
-
const content = await fs.promises.readFile(filePath);
|
|
78
|
-
const parsed = await simpleParser(content);
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
subject: parsed.subject || '',
|
|
82
|
-
inReplyTo: parsed.inReplyTo || null,
|
|
83
|
-
headers: convertHeaders(parsed)
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
test('RFC 3834 autoreply detection tests', async t => {
|
|
88
|
-
await t.test('Auto-Submitted header detection (rfc3834-01)', async () => {
|
|
89
|
-
const messageData = await parseForAutoreply(path('rfc3834-01.eml'));
|
|
90
|
-
const result = isAutoreply(messageData);
|
|
91
|
-
|
|
92
|
-
// Has Auto-Submitted: auto-replied header
|
|
93
|
-
assert.strictEqual(result, true);
|
|
94
|
-
assert.ok(messageData.headers['auto-submitted']);
|
|
95
|
-
assert.ok(messageData.headers['auto-submitted'].some(e => /auto-replied/.test(e)));
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
await t.test('Automatic reply subject with X-Auto-Response-Suppress (rfc3834-02)', async () => {
|
|
99
|
-
const messageData = await parseForAutoreply(path('rfc3834-02.eml'));
|
|
100
|
-
const result = isAutoreply(messageData);
|
|
101
|
-
|
|
102
|
-
// Has subject "Automatic reply:" and X-Auto-Response-Suppress: All
|
|
103
|
-
assert.strictEqual(result, true);
|
|
104
|
-
assert.ok(/^Automatic reply:/i.test(messageData.subject));
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
await t.test('Auto reply subject with In-Reply-To (rfc3834-03)', async () => {
|
|
108
|
-
const messageData = await parseForAutoreply(path('rfc3834-03.eml'));
|
|
109
|
-
const result = isAutoreply(messageData);
|
|
110
|
-
|
|
111
|
-
// Has subject "Auto reply:" with In-Reply-To header
|
|
112
|
-
assert.strictEqual(result, true);
|
|
113
|
-
assert.ok(/^Auto reply:/i.test(messageData.subject));
|
|
114
|
-
assert.ok(messageData.inReplyTo);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
await t.test('Microsoft Exchange automatic reply (rfc3834-04)', async () => {
|
|
118
|
-
const messageData = await parseForAutoreply(path('rfc3834-04.eml'));
|
|
119
|
-
const result = isAutoreply(messageData);
|
|
120
|
-
|
|
121
|
-
// Has subject "Automatic reply:" and X-Auto-Response-Suppress: All
|
|
122
|
-
assert.strictEqual(result, true);
|
|
123
|
-
assert.ok(messageData.headers['x-auto-response-suppress']);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
await t.test('Auto-Submitted with random subject (rfc3834-05)', async () => {
|
|
127
|
-
const messageData = await parseForAutoreply(path('rfc3834-05.eml'));
|
|
128
|
-
const result = isAutoreply(messageData);
|
|
129
|
-
|
|
130
|
-
// Has Auto-Submitted: auto-replied with non-standard subject
|
|
131
|
-
assert.strictEqual(result, true);
|
|
132
|
-
assert.ok(messageData.headers['auto-submitted']);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
await t.test('Mimecast auto-response (rfc3834-06)', async () => {
|
|
136
|
-
const messageData = await parseForAutoreply(path('rfc3834-06.eml'));
|
|
137
|
-
const result = isAutoreply(messageData);
|
|
138
|
-
|
|
139
|
-
// Has Auto-Submitted and X-Auto-Response-Suppress headers
|
|
140
|
-
assert.strictEqual(result, true);
|
|
141
|
-
assert.ok(messageData.headers['auto-submitted']);
|
|
142
|
-
assert.ok(messageData.headers['x-auto-response-suppress']);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('isAutoreply heuristics', async t => {
|
|
147
|
-
await t.test('Detects Out of Office subject', async () => {
|
|
148
|
-
const messageData = {
|
|
149
|
-
subject: 'Out of Office: I am away',
|
|
150
|
-
inReplyTo: null,
|
|
151
|
-
headers: {}
|
|
152
|
-
};
|
|
153
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
await t.test('Detects Out of the Office subject (with "the")', async () => {
|
|
157
|
-
const messageData = {
|
|
158
|
-
subject: 'Out of the Office: Mailtrain Newsletter',
|
|
159
|
-
inReplyTo: null,
|
|
160
|
-
headers: {}
|
|
161
|
-
};
|
|
162
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
await t.test('Detects OOF prefix', async () => {
|
|
166
|
-
const messageData = {
|
|
167
|
-
subject: 'OOF: Automatic Reply',
|
|
168
|
-
inReplyTo: null,
|
|
169
|
-
headers: {}
|
|
170
|
-
};
|
|
171
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
await t.test('Detects OOO prefix', async () => {
|
|
175
|
-
const messageData = {
|
|
176
|
-
subject: 'OOO: Out of Office',
|
|
177
|
-
inReplyTo: null,
|
|
178
|
-
headers: {}
|
|
179
|
-
};
|
|
180
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
await t.test('Detects Automatic reply subject', async () => {
|
|
184
|
-
const messageData = {
|
|
185
|
-
subject: 'Automatic reply: Your message',
|
|
186
|
-
inReplyTo: null,
|
|
187
|
-
headers: {}
|
|
188
|
-
};
|
|
189
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
await t.test('Detects Auto reply subject (with space)', async () => {
|
|
193
|
-
const messageData = {
|
|
194
|
-
subject: 'Auto reply: Thanks',
|
|
195
|
-
inReplyTo: null,
|
|
196
|
-
headers: {}
|
|
197
|
-
};
|
|
198
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
await t.test('Detects Automatic response subject', async () => {
|
|
202
|
-
const messageData = {
|
|
203
|
-
subject: 'Automatic response: Meeting',
|
|
204
|
-
inReplyTo: null,
|
|
205
|
-
headers: {}
|
|
206
|
-
};
|
|
207
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
await t.test('Requires inReplyTo for weak auto: subject', async () => {
|
|
211
|
-
const messageData = {
|
|
212
|
-
subject: 'auto: Something',
|
|
213
|
-
inReplyTo: null,
|
|
214
|
-
headers: {}
|
|
215
|
-
};
|
|
216
|
-
assert.strictEqual(isAutoreply(messageData), false);
|
|
217
|
-
|
|
218
|
-
messageData.inReplyTo = '<some-message-id@example.com>';
|
|
219
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
await t.test('Detects Precedence: auto_reply header', async () => {
|
|
223
|
-
const messageData = {
|
|
224
|
-
subject: 'Some subject',
|
|
225
|
-
inReplyTo: null,
|
|
226
|
-
headers: {
|
|
227
|
-
precedence: ['auto_reply']
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
await t.test('Detects Precedence: auto-reply header', async () => {
|
|
234
|
-
const messageData = {
|
|
235
|
-
subject: 'Some subject',
|
|
236
|
-
inReplyTo: null,
|
|
237
|
-
headers: {
|
|
238
|
-
precedence: ['auto-reply']
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
await t.test('Detects Auto-Submitted: auto-replied header', async () => {
|
|
245
|
-
const messageData = {
|
|
246
|
-
subject: 'Some subject',
|
|
247
|
-
inReplyTo: null,
|
|
248
|
-
headers: {
|
|
249
|
-
'auto-submitted': ['auto-replied']
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
await t.test('Detects X-Auto-Response-Suppress header', async () => {
|
|
256
|
-
const messageData = {
|
|
257
|
-
subject: 'Some subject',
|
|
258
|
-
inReplyTo: null,
|
|
259
|
-
headers: {
|
|
260
|
-
'x-auto-response-suppress': ['All']
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
await t.test('Detects X-Autoresponder header', async () => {
|
|
267
|
-
const messageData = {
|
|
268
|
-
subject: 'Some subject',
|
|
269
|
-
inReplyTo: null,
|
|
270
|
-
headers: {
|
|
271
|
-
'x-autoresponder': ['true']
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
await t.test('Detects X-Autorespond header', async () => {
|
|
278
|
-
const messageData = {
|
|
279
|
-
subject: 'Some subject',
|
|
280
|
-
inReplyTo: null,
|
|
281
|
-
headers: {
|
|
282
|
-
'x-autorespond': ['yes']
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
await t.test('Detects X-Autoreply header', async () => {
|
|
289
|
-
const messageData = {
|
|
290
|
-
subject: 'Some subject',
|
|
291
|
-
inReplyTo: null,
|
|
292
|
-
headers: {
|
|
293
|
-
'x-autoreply': ['yes']
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
assert.strictEqual(isAutoreply(messageData), true);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
await t.test('Rejects regular email', async () => {
|
|
300
|
-
const messageData = {
|
|
301
|
-
subject: 'Weekly Newsletter',
|
|
302
|
-
inReplyTo: null,
|
|
303
|
-
headers: {
|
|
304
|
-
from: ['newsletter@example.com']
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
assert.strictEqual(isAutoreply(messageData), false);
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
await t.test('Rejects email with similar but non-matching subject', async () => {
|
|
311
|
-
const messageData = {
|
|
312
|
-
subject: 'Automatic update notification',
|
|
313
|
-
inReplyTo: null,
|
|
314
|
-
headers: {}
|
|
315
|
-
};
|
|
316
|
-
assert.strictEqual(isAutoreply(messageData), false);
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
await t.test('Handles missing headers gracefully', async () => {
|
|
320
|
-
const messageData = {
|
|
321
|
-
subject: 'Test',
|
|
322
|
-
inReplyTo: null,
|
|
323
|
-
headers: null
|
|
324
|
-
};
|
|
325
|
-
assert.strictEqual(isAutoreply(messageData), false);
|
|
326
|
-
});
|
|
327
|
-
});
|
package/test/bounce-test.js
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const test = require('node:test');
|
|
4
|
-
const assert = require('node:assert').strict;
|
|
5
|
-
|
|
6
|
-
const { bounceDetect } = require('../lib/bounce-detect');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
|
|
9
|
-
const Path = require('path');
|
|
10
|
-
const path = fname => Path.join(__dirname, 'fixtures', 'bounces', fname);
|
|
11
|
-
|
|
12
|
-
test('Bounce parsing tests', async t => {
|
|
13
|
-
await t.test('163', async () => {
|
|
14
|
-
const content = await fs.promises.readFile(path('163.eml'));
|
|
15
|
-
const bounce = await bounceDetect(content);
|
|
16
|
-
|
|
17
|
-
assert.strictEqual(bounce.recipient, 'jgfhhoiyfjhhugjhv@ethereal.email');
|
|
18
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
19
|
-
assert.strictEqual(bounce.response.message, 'SMTP error, RCPT TO: Host ethereal.email(54.36.85.113) RCPT TO said 550 No such user here');
|
|
20
|
-
assert.strictEqual(bounce.messageId, '<cc799ab9-ab11-0960-f3c2-2e4b9a5e8fb6@163.com>');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
await t.test('fastmail', async () => {
|
|
24
|
-
const content = await fs.promises.readFile(path('fastmail.eml'));
|
|
25
|
-
const bounce = await bounceDetect(content);
|
|
26
|
-
|
|
27
|
-
assert.strictEqual(bounce.recipient, 'htfgvhyufthdgcvhgjyfthgc@ethereal.email');
|
|
28
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
29
|
-
assert.strictEqual(bounce.response.message, '550 No such user here');
|
|
30
|
-
assert.strictEqual(bounce.messageId, '<e85f1c9b-9b51-4028-8ec0-0a657155028e@app.fastmail.com>');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
await t.test('gmail', async () => {
|
|
34
|
-
const content = await fs.promises.readFile(path('gmail.eml'));
|
|
35
|
-
const bounce = await bounceDetect(content);
|
|
36
|
-
|
|
37
|
-
assert.strictEqual(bounce.recipient, 'jhfthgfuyfhvjkugjhvjuyfv@hot.ee');
|
|
38
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
39
|
-
assert.strictEqual(
|
|
40
|
-
bounce.response.message,
|
|
41
|
-
'550 5.1.1 <jhfthgfuyfhvjkugjhvjuyfv@hot.ee>: Recipient address rejected: User unknown in relay recipient table'
|
|
42
|
-
);
|
|
43
|
-
assert.strictEqual(bounce.messageId, '<CAPacwgw3pCyVcmW4nVy8VPX5u5ksn_wZB2jZ_tLUM2es7LaiEA@mail.gmail.com>');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
await t.test('hotmail', async () => {
|
|
47
|
-
const content = await fs.promises.readFile(path('hotmail.eml'));
|
|
48
|
-
const bounce = await bounceDetect(content);
|
|
49
|
-
|
|
50
|
-
assert.strictEqual(bounce.recipient, 'sdfadsdfwedsfcasfeqwefwq@hot.ee');
|
|
51
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
52
|
-
assert.strictEqual(
|
|
53
|
-
bounce.response.message,
|
|
54
|
-
'550 5.1.1 <sdfadsdfwedsfcasfeqwefwq@hot.ee>: Recipient address rejected: User unknown in relay recipient table'
|
|
55
|
-
);
|
|
56
|
-
assert.strictEqual(bounce.messageId, '<DB6PR0902MB194406730EDCF3E12EE16DCF90209@DB6PR0902MB1944.eurprd09.prod.outlook.com>');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
await t.test('mailru', async () => {
|
|
60
|
-
const content = await fs.promises.readFile(path('mailru.eml'));
|
|
61
|
-
const bounce = await bounceDetect(content);
|
|
62
|
-
|
|
63
|
-
assert.strictEqual(bounce.recipient, 'tfhgyuftghjyftghv@hot.ee');
|
|
64
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
65
|
-
assert.strictEqual(bounce.response.message, '550 5.1.1 <tfhgyuftghjyftghv@hot.ee>: Recipient address rejected: User unknown in relay recipient table');
|
|
66
|
-
assert.strictEqual(bounce.messageId, '<1665380146.431729680@f705.i.mail.ru>');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
await t.test('outlook', async () => {
|
|
70
|
-
const content = await fs.promises.readFile(path('outlook.eml'));
|
|
71
|
-
const bounce = await bounceDetect(content);
|
|
72
|
-
|
|
73
|
-
assert.strictEqual(bounce.recipient, 'wfsddaSdasffasdqwqw@hot.ee');
|
|
74
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
75
|
-
assert.strictEqual(
|
|
76
|
-
bounce.response.message,
|
|
77
|
-
'550 5.1.1 <wfsddaSdasffasdqwqw@hot.ee>: Recipient address rejected: User unknown in relay recipient table'
|
|
78
|
-
);
|
|
79
|
-
assert.strictEqual(bounce.messageId, '<PR1PR07MB57558E5D11D6C2BA6F950391D7209@PR1PR07MB5755.eurprd07.prod.outlook.com>');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
await t.test('postfix', async () => {
|
|
83
|
-
const content = await fs.promises.readFile(path('postfix.eml'));
|
|
84
|
-
const bounce = await bounceDetect(content);
|
|
85
|
-
|
|
86
|
-
assert.strictEqual(bounce.recipient, 'sdagfsdfgdasfsdf@hot.ee');
|
|
87
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
88
|
-
assert.strictEqual(bounce.response.message, '550 5.1.1 <sdagfsdfgdasfsdf@hot.ee>: Recipient address rejected: User unknown in relay recipient table');
|
|
89
|
-
assert.strictEqual(bounce.queueId, 'DF59B82305');
|
|
90
|
-
assert.strictEqual(bounce.messageId, '<0f51267b17be7a93bb0017205b6c4fca@ekiri.ee>');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
await t.test('rambler', async () => {
|
|
94
|
-
const content = await fs.promises.readFile(path('rambler.eml'));
|
|
95
|
-
const bounce = await bounceDetect(content);
|
|
96
|
-
|
|
97
|
-
assert.strictEqual(bounce.recipient, 'yhfgcvjyutfdchgyufthgc@ethereal.email');
|
|
98
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
99
|
-
assert.strictEqual(bounce.response.message, '550 No such user here');
|
|
100
|
-
assert.strictEqual(bounce.messageId, '<18c57ad7166403358c3893f62d7e3a7f@mail.rambler.ru>');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
await t.test('workmail', async () => {
|
|
104
|
-
const content = await fs.promises.readFile(path('workmail.eml'));
|
|
105
|
-
const bounce = await bounceDetect(content);
|
|
106
|
-
|
|
107
|
-
assert.strictEqual(bounce.recipient, 'gfdutydrfghutydrfcuftydh@hot.ee');
|
|
108
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
109
|
-
assert.strictEqual(
|
|
110
|
-
bounce.response.message,
|
|
111
|
-
'550 5.1.1 <gfdutydrfghutydrfcuftydh@hot.ee>: Recipient address rejected: User unknown in relay recipient table'
|
|
112
|
-
);
|
|
113
|
-
assert.strictEqual(bounce.messageId, '<mail.6343b157.093e.5156c64350ef7e50@storage.wm.amazon.com>');
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
await t.test('Yahoo', async () => {
|
|
117
|
-
const content = await fs.promises.readFile(path('yahoo.eml'));
|
|
118
|
-
const bounce = await bounceDetect(content);
|
|
119
|
-
|
|
120
|
-
assert.strictEqual(bounce.recipient, 'thgdcgrfchvutycfgxcvg@hot.ee');
|
|
121
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
122
|
-
assert.strictEqual(
|
|
123
|
-
bounce.response.message,
|
|
124
|
-
'550: 5.1.1 <thgdcgrfchvutycfgxcvg@hot.ee>: Recipient address rejected: User unknown in relay recipient table'
|
|
125
|
-
);
|
|
126
|
-
assert.strictEqual(bounce.messageId, '<1956854879.3770605.1665380049620@mail.yahoo.com>');
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
await t.test('zonemta', async () => {
|
|
130
|
-
const content = await fs.promises.readFile(path('zonemta.eml'));
|
|
131
|
-
const bounce = await bounceDetect(content);
|
|
132
|
-
|
|
133
|
-
assert.strictEqual(bounce.recipient, 'sdffasdfgfasfadas@hot.ee');
|
|
134
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
135
|
-
assert.strictEqual(bounce.response.message, '550 5.1.1 <sdffasdfgfasfadas@hot.ee>: Recipient address rejected: User unknown in relay recipient table');
|
|
136
|
-
assert.strictEqual(bounce.messageId, '<48a84e64-d471-cfa6-3ea5-f10cd8571135@zone.ee>');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
await t.test('zoho', async () => {
|
|
140
|
-
const content = await fs.promises.readFile(path('zoho.eml'));
|
|
141
|
-
const bounce = await bounceDetect(content);
|
|
142
|
-
|
|
143
|
-
assert.strictEqual(bounce.recipient, 'recipient@example.com');
|
|
144
|
-
assert.strictEqual(bounce.action, 'failed');
|
|
145
|
-
assert.strictEqual(
|
|
146
|
-
bounce.response.message,
|
|
147
|
-
'5.2.1 The email account that you tried to reach is disabled. Learn more at 5.2.1 https://support.google.com/mail/?p=DisabledUser j8-20020a170903024800b001946612570csi19333477plh.316 - gsmtp'
|
|
148
|
-
);
|
|
149
|
-
assert.strictEqual(bounce.messageId, '<63d982c2660381675199170@smtppro.zoho.com>');
|
|
150
|
-
});
|
|
151
|
-
});
|