@dawnlit/outlook-bridge 1.0.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/LICENSE +190 -0
- package/README.md +253 -0
- package/dist/OutlookService.d.ts +43 -0
- package/dist/OutlookService.js +137 -0
- package/dist/OutlookService.js.map +1 -0
- package/dist/errors.d.ts +112 -0
- package/dist/errors.js +140 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/mac/accounts.d.ts +5 -0
- package/dist/mac/accounts.js +17 -0
- package/dist/mac/accounts.js.map +1 -0
- package/dist/mac/attachments.d.ts +28 -0
- package/dist/mac/attachments.js +120 -0
- package/dist/mac/attachments.js.map +1 -0
- package/dist/mac/bounces.d.ts +32 -0
- package/dist/mac/bounces.js +285 -0
- package/dist/mac/bounces.js.map +1 -0
- package/dist/mac/cleanup.d.ts +29 -0
- package/dist/mac/cleanup.js +219 -0
- package/dist/mac/cleanup.js.map +1 -0
- package/dist/mac/drafts.d.ts +27 -0
- package/dist/mac/drafts.js +214 -0
- package/dist/mac/drafts.js.map +1 -0
- package/dist/mac/folders.d.ts +28 -0
- package/dist/mac/folders.js +127 -0
- package/dist/mac/folders.js.map +1 -0
- package/dist/mac/index.d.ts +22 -0
- package/dist/mac/index.js +119 -0
- package/dist/mac/index.js.map +1 -0
- package/dist/mac/read.d.ts +46 -0
- package/dist/mac/read.js +406 -0
- package/dist/mac/read.js.map +1 -0
- package/dist/mac/run.d.ts +64 -0
- package/dist/mac/run.js +250 -0
- package/dist/mac/run.js.map +1 -0
- package/dist/mac/scripts.d.ts +137 -0
- package/dist/mac/scripts.js +337 -0
- package/dist/mac/scripts.js.map +1 -0
- package/dist/mac/send.d.ts +23 -0
- package/dist/mac/send.js +135 -0
- package/dist/mac/send.js.map +1 -0
- package/dist/mac/signatures.d.ts +4 -0
- package/dist/mac/signatures.js +36 -0
- package/dist/mac/signatures.js.map +1 -0
- package/dist/mac/templates.d.ts +34 -0
- package/dist/mac/templates.js +266 -0
- package/dist/mac/templates.js.map +1 -0
- package/dist/mail.d.ts +72 -0
- package/dist/mail.js +131 -0
- package/dist/mail.js.map +1 -0
- package/dist/outlookTemplateSections.d.ts +62 -0
- package/dist/outlookTemplateSections.js +313 -0
- package/dist/outlookTemplateSections.js.map +1 -0
- package/dist/runtime.d.ts +76 -0
- package/dist/runtime.js +123 -0
- package/dist/runtime.js.map +1 -0
- package/dist/shared/attachmentMatch.d.ts +32 -0
- package/dist/shared/attachmentMatch.js +50 -0
- package/dist/shared/attachmentMatch.js.map +1 -0
- package/dist/shared/bounceRules.d.ts +33 -0
- package/dist/shared/bounceRules.js +104 -0
- package/dist/shared/bounceRules.js.map +1 -0
- package/dist/shared/capabilities.d.ts +3 -0
- package/dist/shared/capabilities.js +9 -0
- package/dist/shared/capabilities.js.map +1 -0
- package/dist/shared/json.d.ts +11 -0
- package/dist/shared/json.js +45 -0
- package/dist/shared/json.js.map +1 -0
- package/dist/shared/replyBody.d.ts +49 -0
- package/dist/shared/replyBody.js +113 -0
- package/dist/shared/replyBody.js.map +1 -0
- package/dist/types.d.ts +365 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/windows/accounts.d.ts +2 -0
- package/dist/windows/accounts.js +22 -0
- package/dist/windows/accounts.js.map +1 -0
- package/dist/windows/attachments.d.ts +28 -0
- package/dist/windows/attachments.js +141 -0
- package/dist/windows/attachments.js.map +1 -0
- package/dist/windows/bounces.d.ts +34 -0
- package/dist/windows/bounces.js +267 -0
- package/dist/windows/bounces.js.map +1 -0
- package/dist/windows/cleanup.d.ts +29 -0
- package/dist/windows/cleanup.js +165 -0
- package/dist/windows/cleanup.js.map +1 -0
- package/dist/windows/drafts.d.ts +29 -0
- package/dist/windows/drafts.js +253 -0
- package/dist/windows/drafts.js.map +1 -0
- package/dist/windows/folders.d.ts +16 -0
- package/dist/windows/folders.js +88 -0
- package/dist/windows/folders.js.map +1 -0
- package/dist/windows/index.d.ts +27 -0
- package/dist/windows/index.js +100 -0
- package/dist/windows/index.js.map +1 -0
- package/dist/windows/read.d.ts +54 -0
- package/dist/windows/read.js +372 -0
- package/dist/windows/read.js.map +1 -0
- package/dist/windows/run.d.ts +54 -0
- package/dist/windows/run.js +161 -0
- package/dist/windows/run.js.map +1 -0
- package/dist/windows/scripts.d.ts +56 -0
- package/dist/windows/scripts.js +163 -0
- package/dist/windows/scripts.js.map +1 -0
- package/dist/windows/send.d.ts +11 -0
- package/dist/windows/send.js +114 -0
- package/dist/windows/send.js.map +1 -0
- package/dist/windows/signatures.d.ts +14 -0
- package/dist/windows/signatures.js +69 -0
- package/dist/windows/signatures.js.map +1 -0
- package/dist/windows/templates.d.ts +25 -0
- package/dist/windows/templates.js +246 -0
- package/dist/windows/templates.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cleanUndeliverableEmails = cleanUndeliverableEmails;
|
|
4
|
+
exports.collectBouncedRecipients = collectBouncedRecipients;
|
|
5
|
+
exports.readSentRecipientGroups = readSentRecipientGroups;
|
|
6
|
+
// Bounce-backs: finding them, filing them away, and mining them for the
|
|
7
|
+
// addresses that failed.
|
|
8
|
+
const run_1 = require("./run");
|
|
9
|
+
const scripts_1 = require("./scripts");
|
|
10
|
+
const json_1 = require("../shared/json");
|
|
11
|
+
const bounceRules_1 = require("../shared/bounceRules");
|
|
12
|
+
const mail_1 = require("../mail");
|
|
13
|
+
/**
|
|
14
|
+
* The classifier lists, generated from the shared rules so Windows and macOS
|
|
15
|
+
* cannot come to disagree about what a bounce is. Emitted once per script,
|
|
16
|
+
* before the item loop.
|
|
17
|
+
*/
|
|
18
|
+
const BOUNCE_LISTS_PS = `
|
|
19
|
+
$phrases = @(${(0, run_1.psList)(bounceRules_1.BOUNCE_SUBJECT_PHRASES)})
|
|
20
|
+
$daemonAddr = @(${(0, run_1.psList)(bounceRules_1.BOUNCE_DAEMON_ADDRESSES)})
|
|
21
|
+
$daemonName = @(${(0, run_1.psList)(bounceRules_1.BOUNCE_DAEMON_NAMES)})
|
|
22
|
+
`;
|
|
23
|
+
/**
|
|
24
|
+
* Per-item classifier. Given an Outlook item in `$item` and the account address
|
|
25
|
+
* (lowercased) in `$targetLc`, sets `$reason` to why it's a bounce ('' if not)
|
|
26
|
+
* and fills `$failedRcpts` with the recipient addresses parsed from the bounce
|
|
27
|
+
* body. Also leaves `$subj`/`$sName`/`$sEmail` populated for the caller's report.
|
|
28
|
+
*
|
|
29
|
+
* The body is only read once a cheaper signal (class/sender/subject) has already
|
|
30
|
+
* matched — that ordering is what keeps a large-inbox scan affordable.
|
|
31
|
+
*/
|
|
32
|
+
const BOUNCE_CLASSIFY_PS = `
|
|
33
|
+
$reason = ''
|
|
34
|
+
$failedRcpts = @()
|
|
35
|
+
$subj = ''
|
|
36
|
+
$sName = ''
|
|
37
|
+
$sEmail = ''
|
|
38
|
+
$cls = 0
|
|
39
|
+
try { $cls = [int]$item.Class } catch {}
|
|
40
|
+
if ($cls -eq 43 -or $cls -eq 46) {
|
|
41
|
+
try { if ($item.Subject) { $subj = [string]$item.Subject } } catch {}
|
|
42
|
+
$subjLc = $subj.ToLower()
|
|
43
|
+
try { if ($item.SenderName) { $sName = [string]$item.SenderName } } catch {}
|
|
44
|
+
$sNameLc = $sName.ToLower()
|
|
45
|
+
try { if ($item.SenderEmailAddress) { $sEmail = [string]$item.SenderEmailAddress } } catch {}
|
|
46
|
+
$sEmailLc = $sEmail.ToLower()
|
|
47
|
+
$msgClass = ''
|
|
48
|
+
try { $msgClass = [string]$item.MessageClass } catch {}
|
|
49
|
+
if ($msgClass -like '${bounceRules_1.NDR_MESSAGE_CLASS_PREFIX}*') { $reason = 'Non-delivery report (NDR)' }
|
|
50
|
+
if ($reason -eq '') { foreach ($d in $daemonAddr) { if ($sEmailLc.Contains($d)) { $reason = 'From mail-delivery system'; break } } }
|
|
51
|
+
if ($reason -eq '') { foreach ($d in $daemonName) { if ($sNameLc.Contains($d)) { $reason = 'From mail-delivery system'; break } } }
|
|
52
|
+
if ($reason -eq '') { foreach ($p in $phrases) { if ($subjLc.Contains($p)) { $reason = "Bounce subject phrase: '$p'"; break } } }
|
|
53
|
+
if ($reason -ne '') {
|
|
54
|
+
$bodyRaw = ''
|
|
55
|
+
try { if ($item.Body) { $bodyRaw = [string]$item.Body } } catch {}
|
|
56
|
+
if ($bodyRaw -ne '') {
|
|
57
|
+
$mm = [regex]::Matches($bodyRaw, '${bounceRules_1.BODY_ADDRESS_PATTERN}')
|
|
58
|
+
foreach ($m in $mm) {
|
|
59
|
+
$addr = $m.Value.ToLower().TrimEnd('.')
|
|
60
|
+
if ($addr -eq $targetLc) { continue }
|
|
61
|
+
if ($addr.Contains('mailer-daemon') -or $addr.Contains('postmaster') -or $addr.Contains('mail-daemon')) { continue }
|
|
62
|
+
if ($failedRcpts -notcontains $addr) { $failedRcpts += $addr }
|
|
63
|
+
if ($failedRcpts.Count -ge 5) { break }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
/**
|
|
70
|
+
* Scan an account's inbox for bounce-back / non-delivery messages — Outlook NDRs,
|
|
71
|
+
* mail-daemon/postmaster rejections, and "Message blocked"-style Google/O365
|
|
72
|
+
* failure notices — and, unless previewing, move each to Deleted Items (recoverable).
|
|
73
|
+
*
|
|
74
|
+
* Classification is deliberately conservative so ordinary mail that merely
|
|
75
|
+
* mentions "delivery" is never caught: an item matches only when its
|
|
76
|
+
* MessageClass is an NDR report, its sender fingerprints as a mail-delivery
|
|
77
|
+
* daemon/postmaster, or its subject contains a specific bounce phrase.
|
|
78
|
+
*
|
|
79
|
+
* Matched item references are snapshotted before any Delete() call — deleting
|
|
80
|
+
* mutates the folder collection, so deleting mid-enumeration would skip items
|
|
81
|
+
* (same pattern as sendAllDrafts).
|
|
82
|
+
*/
|
|
83
|
+
async function cleanUndeliverableEmails(emailAccount, daysBack = 30, dryRun = true) {
|
|
84
|
+
(0, run_1.requireWindows)();
|
|
85
|
+
const days = (0, mail_1.clamp)(daysBack, 1, 365);
|
|
86
|
+
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
87
|
+
$dryRun = ${(0, run_1.psBool)(dryRun)}
|
|
88
|
+
${(0, scripts_1.namedStoreScript)(emailAccount)}
|
|
89
|
+
$inbox = $store.GetDefaultFolder(6)
|
|
90
|
+
$cutoff = (Get-Date).AddDays(-${days}).ToString('MM/dd/yyyy HH:mm')
|
|
91
|
+
$filtered = $inbox.Items.Restrict("[ReceivedTime] >= '$cutoff'")
|
|
92
|
+
${BOUNCE_LISTS_PS}
|
|
93
|
+
$targetLc = $target.ToLower()
|
|
94
|
+
$matched = @() # snapshot of COM item refs to (optionally) delete afterward
|
|
95
|
+
$report = @()
|
|
96
|
+
$count = $filtered.Count
|
|
97
|
+
for ($i = 1; $i -le $count; $i++) {
|
|
98
|
+
$item = $null
|
|
99
|
+
try { $item = $filtered.Item($i) } catch { continue }
|
|
100
|
+
if ($item -eq $null) { continue }
|
|
101
|
+
${BOUNCE_CLASSIFY_PS}
|
|
102
|
+
if ($reason -eq '') { continue }
|
|
103
|
+
|
|
104
|
+
$rt = ''
|
|
105
|
+
try { $rt = $item.ReceivedTime.ToString('yyyy-MM-dd HH:mm') } catch {}
|
|
106
|
+
$report += [PSCustomObject]@{
|
|
107
|
+
entryId = $item.EntryID
|
|
108
|
+
subject = $subj.Trim()
|
|
109
|
+
senderName = $sName
|
|
110
|
+
senderEmail = $sEmail
|
|
111
|
+
receivedTime = $rt
|
|
112
|
+
matchedReason = $reason
|
|
113
|
+
failedRecipients = @($failedRcpts)
|
|
114
|
+
}
|
|
115
|
+
$matched += $item
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
$deleted = 0
|
|
119
|
+
$failed = @()
|
|
120
|
+
if (-not $dryRun) {
|
|
121
|
+
foreach ($m in $matched) {
|
|
122
|
+
$s = ''
|
|
123
|
+
try { $s = [string]$m.Subject } catch {}
|
|
124
|
+
try { $m.Delete(); $deleted++ }
|
|
125
|
+
catch { $failed += [PSCustomObject]@{ subject = $s; error = $_.Exception.Message } }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
[PSCustomObject]@{
|
|
130
|
+
account = $target
|
|
131
|
+
scannedDays = ${days}
|
|
132
|
+
dryRun = $dryRun
|
|
133
|
+
matchedCount = $report.Count
|
|
134
|
+
deletedCount = $deleted
|
|
135
|
+
matched = @($report)
|
|
136
|
+
failed = @($failed)
|
|
137
|
+
} | ConvertTo-Json -Depth 4
|
|
138
|
+
`;
|
|
139
|
+
const parsed = (0, json_1.parseObject)(await (0, run_1.runPowerShell)(script, 300000));
|
|
140
|
+
return {
|
|
141
|
+
account: (0, json_1.str)(parsed.account) || emailAccount,
|
|
142
|
+
scannedDays: (0, json_1.num)(parsed.scannedDays) || days,
|
|
143
|
+
dryRun: parsed.dryRun !== false,
|
|
144
|
+
matchedCount: (0, json_1.num)(parsed.matchedCount),
|
|
145
|
+
deletedCount: (0, json_1.num)(parsed.deletedCount),
|
|
146
|
+
matched: (0, json_1.toArray)(parsed.matched).map(m => {
|
|
147
|
+
const e = (0, json_1.record)(m);
|
|
148
|
+
return {
|
|
149
|
+
entryId: (0, json_1.str)(e.entryId),
|
|
150
|
+
subject: (0, json_1.str)(e.subject),
|
|
151
|
+
senderName: (0, json_1.str)(e.senderName),
|
|
152
|
+
senderEmail: (0, json_1.str)(e.senderEmail),
|
|
153
|
+
receivedTime: (0, json_1.str)(e.receivedTime),
|
|
154
|
+
matchedReason: (0, json_1.str)(e.matchedReason),
|
|
155
|
+
failedRecipients: (0, json_1.toArray)(e.failedRecipients).map(json_1.str),
|
|
156
|
+
};
|
|
157
|
+
}),
|
|
158
|
+
failed: (0, json_1.toArray)(parsed.failed).map(f => {
|
|
159
|
+
const e = (0, json_1.record)(f);
|
|
160
|
+
return { subject: (0, json_1.str)(e.subject), error: (0, json_1.str)(e.error) };
|
|
161
|
+
}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Read-only scan of an account's Inbox (and, when scanDeleted, its Deleted Items)
|
|
166
|
+
* for bounce messages, returning just the deduped set of failed recipient
|
|
167
|
+
* addresses. Uses the same conservative classifier as cleanUndeliverableEmails.
|
|
168
|
+
*
|
|
169
|
+
* Deleted Items is included so this still works after cleanUndeliverableEmails has
|
|
170
|
+
* already filed the bounces there — the blacklist step doesn't depend on running
|
|
171
|
+
* before the cleanup. This never deletes anything.
|
|
172
|
+
*/
|
|
173
|
+
async function collectBouncedRecipients(emailAccount, daysBack = 30, scanDeleted = true) {
|
|
174
|
+
if (process.platform !== 'win32')
|
|
175
|
+
return [];
|
|
176
|
+
const days = (0, mail_1.clamp)(daysBack, 1, 365);
|
|
177
|
+
// 6 = Inbox, 3 = Deleted Items.
|
|
178
|
+
const folderIds = scanDeleted ? '@(6, 3)' : '@(6)';
|
|
179
|
+
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
180
|
+
${scripts_1.DELIVERY_STORE_PS}
|
|
181
|
+
$cutoff = (Get-Date).AddDays(-${days}).ToString('MM/dd/yyyy HH:mm')
|
|
182
|
+
${BOUNCE_LISTS_PS}
|
|
183
|
+
$targetLc = $target.ToLower()
|
|
184
|
+
$found = @{}
|
|
185
|
+
foreach ($fid in ${folderIds}) {
|
|
186
|
+
$folder = $null
|
|
187
|
+
try { $folder = $store.GetDefaultFolder($fid) } catch {}
|
|
188
|
+
if ($folder -eq $null) { continue }
|
|
189
|
+
$filtered = $folder.Items.Restrict("[ReceivedTime] >= '$cutoff'")
|
|
190
|
+
$count = $filtered.Count
|
|
191
|
+
for ($i = 1; $i -le $count; $i++) {
|
|
192
|
+
$item = $null
|
|
193
|
+
try { $item = $filtered.Item($i) } catch { continue }
|
|
194
|
+
if ($item -eq $null) { continue }
|
|
195
|
+
${BOUNCE_CLASSIFY_PS}
|
|
196
|
+
if ($reason -eq '') { continue }
|
|
197
|
+
foreach ($a in $failedRcpts) { $found[$a] = $true }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
ConvertTo-Json @($found.Keys) -Depth 2
|
|
201
|
+
`;
|
|
202
|
+
return (0, json_1.parseArray)(await (0, run_1.runPowerShell)(script, 300000)).map(json_1.str).filter(Boolean);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Read the account's Sent Items within the window, returning each mail with the
|
|
206
|
+
* full SMTP address set it was sent to (To + CC + BCC), newest first. This is how
|
|
207
|
+
* the "was every address for this contact tried?" question gets answered: where a
|
|
208
|
+
* blast sends one email per organization addressed to all of its addresses, a sent
|
|
209
|
+
* message's recipient set IS that organization's full address set.
|
|
210
|
+
*/
|
|
211
|
+
async function readSentRecipientGroups(emailAccount, daysBack = 30, limit = 3000) {
|
|
212
|
+
if (process.platform !== 'win32')
|
|
213
|
+
return [];
|
|
214
|
+
const days = (0, mail_1.clamp)(daysBack, 1, 365);
|
|
215
|
+
const cap = (0, mail_1.clamp)(limit, 1, 10000);
|
|
216
|
+
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
217
|
+
$sent = $account.DeliveryStore.GetDefaultFolder(5) # olFolderSentMail
|
|
218
|
+
$cutoff = (Get-Date).AddDays(-${days}).ToString('MM/dd/yyyy HH:mm')
|
|
219
|
+
$items = $sent.Items.Restrict("[SentOn] >= '$cutoff'")
|
|
220
|
+
$items.Sort('[SentOn]', $true)
|
|
221
|
+
$results = @()
|
|
222
|
+
$count = [Math]::Min($items.Count, ${cap})
|
|
223
|
+
for ($i = 1; $i -le $count; $i++) {
|
|
224
|
+
$m = $null
|
|
225
|
+
try { $m = $items.Item($i) } catch { continue }
|
|
226
|
+
if ($m -eq $null) { continue }
|
|
227
|
+
$cls = 0
|
|
228
|
+
try { $cls = [int]$m.Class } catch {}
|
|
229
|
+
if ($cls -ne 43) { continue } # olMail only
|
|
230
|
+
$addrs = @()
|
|
231
|
+
try {
|
|
232
|
+
foreach ($r in $m.Recipients) {
|
|
233
|
+
$addr = ''
|
|
234
|
+
try { $addr = [string]$r.Address } catch {}
|
|
235
|
+
# Internal recipients resolve to an Exchange DN, not SMTP — recover the
|
|
236
|
+
# real address so external correlation still works.
|
|
237
|
+
if ($addr -notlike '*@*') {
|
|
238
|
+
try { $addr = [string]$r.AddressEntry.GetExchangeUser().PrimarySmtpAddress } catch {}
|
|
239
|
+
}
|
|
240
|
+
if ($addr -like '*@*') { $addrs += $addr.ToLower() }
|
|
241
|
+
}
|
|
242
|
+
} catch {}
|
|
243
|
+
if ($addrs.Count -eq 0) { continue }
|
|
244
|
+
$sentOn = ''
|
|
245
|
+
try { $sentOn = $m.SentOn.ToString('yyyy-MM-dd HH:mm') } catch {}
|
|
246
|
+
$subj = ''
|
|
247
|
+
try { if ($m.Subject) { $subj = [string]$m.Subject } } catch {}
|
|
248
|
+
$results += [PSCustomObject]@{
|
|
249
|
+
entryId = $m.EntryID
|
|
250
|
+
subject = $subj.Trim()
|
|
251
|
+
sentOn = $sentOn
|
|
252
|
+
recipients = @($addrs)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
ConvertTo-Json @($results) -Depth 4
|
|
256
|
+
`;
|
|
257
|
+
return (0, json_1.parseArray)(await (0, run_1.runPowerShell)(script, 300000)).map(it => {
|
|
258
|
+
const e = (0, json_1.record)(it);
|
|
259
|
+
return {
|
|
260
|
+
entryId: (0, json_1.str)(e.entryId),
|
|
261
|
+
subject: (0, json_1.str)(e.subject),
|
|
262
|
+
sentOn: (0, json_1.str)(e.sentOn),
|
|
263
|
+
recipients: (0, json_1.toArray)(e.recipients).map(json_1.str),
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=bounces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounces.js","sourceRoot":"","sources":["../../src/windows/bounces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DeleteMailOptions, DeleteMailResult, PurgeDeletedItemsResult } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Delete mail by EntryID from anywhere in the account. Delete() moves each item to
|
|
4
|
+
* Deleted Items, so this is recoverable — purgeDeletedItems is what destroys.
|
|
5
|
+
*
|
|
6
|
+
* ⚠️ This is the one tool here that can reach received mail, and EntryIDs are a
|
|
7
|
+
* genuinely unsafe key for it: GetItemFromID silently returns a DIFFERENT message
|
|
8
|
+
* when handed a stale or wrong id, which is common precisely when many replies share
|
|
9
|
+
* one subject (see saveEmailAttachmentDetailed). Three things hold the line:
|
|
10
|
+
*
|
|
11
|
+
* - **Inbox and Sent Items are refused by default, INCLUDING their subfolders** —
|
|
12
|
+
* a filed subfolder is still received mail. `allowProtected` lifts that, and is
|
|
13
|
+
* the caller explicitly taking responsibility.
|
|
14
|
+
* - **`dryRun` resolves and reports without deleting**, so the exact subjects and
|
|
15
|
+
* folders can be shown to the user before anything happens. Use it first.
|
|
16
|
+
* - **Every outcome echoes the subject and folderPath** of the item actually
|
|
17
|
+
* resolved, so a wrong id is visible after the fact rather than silent.
|
|
18
|
+
*/
|
|
19
|
+
export declare function deleteOutlookEmails(emailAccount: string, entryIds: string[], options?: DeleteMailOptions): Promise<DeleteMailResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Permanently remove items from the account's Deleted Items folder. This is the ONE
|
|
22
|
+
* genuinely irreversible operation here — nothing recovers from it — which is why it
|
|
23
|
+
* is folder-scoped rather than keyed on an EntryID: it can only ever destroy what the
|
|
24
|
+
* user already threw away.
|
|
25
|
+
*
|
|
26
|
+
* `olderThanDays` keeps recent items (0 = purge everything). Iterates backwards, as
|
|
27
|
+
* deleting mutates the collection and a forward walk would skip every other item.
|
|
28
|
+
*/
|
|
29
|
+
export declare function purgeDeletedItems(emailAccount: string, olderThanDays?: number, dryRun?: boolean): Promise<PurgeDeletedItemsResult>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteOutlookEmails = deleteOutlookEmails;
|
|
4
|
+
exports.purgeDeletedItems = purgeDeletedItems;
|
|
5
|
+
// Deleting mail, and emptying what was already deleted.
|
|
6
|
+
const run_1 = require("./run");
|
|
7
|
+
const scripts_1 = require("./scripts");
|
|
8
|
+
const json_1 = require("../shared/json");
|
|
9
|
+
const mail_1 = require("../mail");
|
|
10
|
+
/** Folders whose contents are received or already-sent mail, not working state. */
|
|
11
|
+
const PROTECTED_FOLDER_IDS = [6, 5];
|
|
12
|
+
/** Walks an item's parent chain, so Inbox/Sent protection covers their subfolders too. */
|
|
13
|
+
const FOLDER_CHAIN_PS = `
|
|
14
|
+
function Get-FolderChainIds($folder) {
|
|
15
|
+
$ids = @()
|
|
16
|
+
$cur = $folder
|
|
17
|
+
$guard = 0
|
|
18
|
+
while ($cur -ne $null -and $guard -lt 25) {
|
|
19
|
+
$cid = $null
|
|
20
|
+
try { $cid = $cur.EntryID } catch { $cid = $null }
|
|
21
|
+
if (-not $cid) { break }
|
|
22
|
+
$ids += $cid
|
|
23
|
+
$parent = $null
|
|
24
|
+
try { $parent = $cur.Parent } catch { $parent = $null }
|
|
25
|
+
if ($parent -eq $null) { break }
|
|
26
|
+
$cur = $parent
|
|
27
|
+
$guard++
|
|
28
|
+
}
|
|
29
|
+
return $ids
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
/**
|
|
33
|
+
* Delete mail by EntryID from anywhere in the account. Delete() moves each item to
|
|
34
|
+
* Deleted Items, so this is recoverable — purgeDeletedItems is what destroys.
|
|
35
|
+
*
|
|
36
|
+
* ⚠️ This is the one tool here that can reach received mail, and EntryIDs are a
|
|
37
|
+
* genuinely unsafe key for it: GetItemFromID silently returns a DIFFERENT message
|
|
38
|
+
* when handed a stale or wrong id, which is common precisely when many replies share
|
|
39
|
+
* one subject (see saveEmailAttachmentDetailed). Three things hold the line:
|
|
40
|
+
*
|
|
41
|
+
* - **Inbox and Sent Items are refused by default, INCLUDING their subfolders** —
|
|
42
|
+
* a filed subfolder is still received mail. `allowProtected` lifts that, and is
|
|
43
|
+
* the caller explicitly taking responsibility.
|
|
44
|
+
* - **`dryRun` resolves and reports without deleting**, so the exact subjects and
|
|
45
|
+
* folders can be shown to the user before anything happens. Use it first.
|
|
46
|
+
* - **Every outcome echoes the subject and folderPath** of the item actually
|
|
47
|
+
* resolved, so a wrong id is visible after the fact rather than silent.
|
|
48
|
+
*/
|
|
49
|
+
async function deleteOutlookEmails(emailAccount, entryIds, options = {}) {
|
|
50
|
+
(0, run_1.requireWindows)();
|
|
51
|
+
const { allowProtected = false, dryRun = false } = options;
|
|
52
|
+
if (entryIds.length === 0) {
|
|
53
|
+
return { dryRun, deleted: 0, refused: 0, failed: 0, items: [] };
|
|
54
|
+
}
|
|
55
|
+
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
56
|
+
${scripts_1.DELIVERY_STORE_PS}
|
|
57
|
+
${FOLDER_CHAIN_PS}
|
|
58
|
+
$protectedIds = @{}
|
|
59
|
+
foreach ($fid in @(${PROTECTED_FOLDER_IDS.join(',')})) {
|
|
60
|
+
try { $protectedIds[$store.GetDefaultFolder($fid).EntryID] = $true } catch {}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
$items = @()
|
|
64
|
+
$deleted = 0
|
|
65
|
+
$refused = 0
|
|
66
|
+
$failed = 0
|
|
67
|
+
foreach ($id in @(${(0, run_1.psList)(entryIds)})) {
|
|
68
|
+
$subject = ''
|
|
69
|
+
$folderPath = ''
|
|
70
|
+
try {
|
|
71
|
+
$it = $null
|
|
72
|
+
try { $it = $ns.GetItemFromID($id, $store.StoreID) } catch { $it = $null }
|
|
73
|
+
if ($it -eq $null) { try { $it = $ns.GetItemFromID($id) } catch { $it = $null } }
|
|
74
|
+
if ($it -eq $null) { throw "no item with that EntryID in this account" }
|
|
75
|
+
try { $subject = $it.Subject } catch {}
|
|
76
|
+
$parent = $null
|
|
77
|
+
try { $parent = $it.Parent } catch {}
|
|
78
|
+
if ($parent -eq $null) { throw "item has no parent folder - refusing to delete" }
|
|
79
|
+
try { $folderPath = $parent.FolderPath } catch {}
|
|
80
|
+
|
|
81
|
+
$chain = Get-FolderChainIds $parent
|
|
82
|
+
$isProtected = $false
|
|
83
|
+
foreach ($cid in $chain) { if ($protectedIds.ContainsKey($cid)) { $isProtected = $true; break } }
|
|
84
|
+
|
|
85
|
+
if ($isProtected -and -not ${(0, run_1.psBool)(allowProtected)}) {
|
|
86
|
+
$refused++
|
|
87
|
+
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'refused'; reason = '${(0, run_1.psEscape)(mail_1.PROTECTED_MAIL_REASON)}' }
|
|
88
|
+
} elseif (${(0, run_1.psBool)(dryRun)}) {
|
|
89
|
+
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'would-delete'; reason = '' }
|
|
90
|
+
} else {
|
|
91
|
+
$it.Delete()
|
|
92
|
+
$deleted++
|
|
93
|
+
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'deleted'; reason = '' }
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
$failed++
|
|
97
|
+
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'failed'; reason = $_.Exception.Message }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
ConvertTo-Json @{ dryRun = ${(0, run_1.psBool)(dryRun)}; deleted = $deleted; refused = $refused; failed = $failed; items = @($items) } -Depth 4
|
|
101
|
+
`;
|
|
102
|
+
const parsed = (0, json_1.parseObject)(await (0, run_1.runPowerShell)(script, 300000));
|
|
103
|
+
return {
|
|
104
|
+
dryRun,
|
|
105
|
+
deleted: (0, json_1.num)(parsed.deleted),
|
|
106
|
+
refused: (0, json_1.num)(parsed.refused),
|
|
107
|
+
failed: (0, json_1.num)(parsed.failed),
|
|
108
|
+
items: (0, json_1.toArray)(parsed.items).map(i => {
|
|
109
|
+
const e = (0, json_1.record)(i);
|
|
110
|
+
return {
|
|
111
|
+
entryId: (0, json_1.str)(e.entryId),
|
|
112
|
+
subject: (0, json_1.str)(e.subject),
|
|
113
|
+
folderPath: (0, json_1.str)(e.folderPath),
|
|
114
|
+
status: ((0, json_1.str)(e.status) || 'failed'),
|
|
115
|
+
reason: (0, json_1.str)(e.reason),
|
|
116
|
+
};
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Permanently remove items from the account's Deleted Items folder. This is the ONE
|
|
122
|
+
* genuinely irreversible operation here — nothing recovers from it — which is why it
|
|
123
|
+
* is folder-scoped rather than keyed on an EntryID: it can only ever destroy what the
|
|
124
|
+
* user already threw away.
|
|
125
|
+
*
|
|
126
|
+
* `olderThanDays` keeps recent items (0 = purge everything). Iterates backwards, as
|
|
127
|
+
* deleting mutates the collection and a forward walk would skip every other item.
|
|
128
|
+
*/
|
|
129
|
+
async function purgeDeletedItems(emailAccount, olderThanDays = 0, dryRun = false) {
|
|
130
|
+
(0, run_1.requireWindows)();
|
|
131
|
+
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
132
|
+
$folder = $account.DeliveryStore.GetDefaultFolder(3)
|
|
133
|
+
$cutoff = (Get-Date).AddDays(-${olderThanDays})
|
|
134
|
+
$matched = 0
|
|
135
|
+
$purged = 0
|
|
136
|
+
$kept = 0
|
|
137
|
+
$failed = 0
|
|
138
|
+
# Bound once: every $folder.Items is a COM property get that materialises a
|
|
139
|
+
# fresh collection object, and this loop runs once per message in Deleted Items.
|
|
140
|
+
$folderItems = $folder.Items
|
|
141
|
+
for ($i = $folderItems.Count; $i -ge 1; $i--) {
|
|
142
|
+
$it = $null
|
|
143
|
+
try { $it = $folderItems.Item($i) } catch { continue }
|
|
144
|
+
$stamp = $null
|
|
145
|
+
foreach ($p in @('ReceivedTime','LastModificationTime','CreationTime')) {
|
|
146
|
+
try { $stamp = $it.$p; if ($stamp -ne $null) { break } } catch {}
|
|
147
|
+
}
|
|
148
|
+
if (${olderThanDays} -gt 0 -and $stamp -ne $null -and $stamp -gt $cutoff) { $kept++; continue }
|
|
149
|
+
$matched++
|
|
150
|
+
if (${(0, run_1.psBool)(dryRun)}) { continue }
|
|
151
|
+
try { $it.Delete(); $purged++ } catch { $failed++ }
|
|
152
|
+
}
|
|
153
|
+
ConvertTo-Json @{ folderPath = $folder.FolderPath; matched = $matched; purged = $purged; kept = $kept; failed = $failed } -Depth 3
|
|
154
|
+
`;
|
|
155
|
+
const parsed = (0, json_1.parseObject)(await (0, run_1.runPowerShell)(script, 600000));
|
|
156
|
+
return {
|
|
157
|
+
folderPath: (0, json_1.str)(parsed.folderPath),
|
|
158
|
+
dryRun,
|
|
159
|
+
matched: (0, json_1.num)(parsed.matched),
|
|
160
|
+
purged: (0, json_1.num)(parsed.purged),
|
|
161
|
+
kept: (0, json_1.num)(parsed.kept),
|
|
162
|
+
failed: (0, json_1.num)(parsed.failed),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/windows/cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DeleteDraftsResult, ListDraftsResult, SendAllDraftsResult } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Send the mail drafts that belong to `emailAccount`, wherever Outlook filed them.
|
|
4
|
+
* Which drafts those are is DRAFTS_SCAN_PS's rule, not this function's.
|
|
5
|
+
*
|
|
6
|
+
* Item references are snapshotted before any Send() call: sending moves an item out
|
|
7
|
+
* of Drafts, and mutating the collection mid-enumeration would skip every other one.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sendAllDrafts(emailAccount: string): Promise<SendAllDraftsResult>;
|
|
10
|
+
/**
|
|
11
|
+
* List the mail drafts belonging to `emailAccount`, newest first. Which drafts
|
|
12
|
+
* those are is DRAFTS_SCAN_PS's rule.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately returns no StoreID: deleteOutlookDrafts re-resolves each EntryID
|
|
15
|
+
* against the same folders, so repeating a ~700-char store id on every row would be
|
|
16
|
+
* pure payload. Bodies are previewed, never returned whole — a templated reply body
|
|
17
|
+
* runs to tens of thousands of characters and a folder's worth would blow the cap.
|
|
18
|
+
*/
|
|
19
|
+
export declare function listOutlookDrafts(emailAccount: string, limit?: number, previewChars?: number): Promise<ListDraftsResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Delete mail drafts by EntryID. Outlook's Delete() moves the item to Deleted Items
|
|
22
|
+
* rather than destroying it, so a mistaken call stays recoverable from there.
|
|
23
|
+
*
|
|
24
|
+
* Every id must resolve to a mail item sitting in one of THIS account's Drafts
|
|
25
|
+
* folders before anything is deleted; an id pointing at ordinary mail, or at another
|
|
26
|
+
* account's draft, is refused and reported. Without that gate this would be a
|
|
27
|
+
* general-purpose "delete any email by id" tool, which is not what it is for.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deleteOutlookDrafts(emailAccount: string, entryIds: string[]): Promise<DeleteDraftsResult>;
|