@dawnlit/outlook-bridge 1.1.1 → 2.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.
Files changed (139) hide show
  1. package/README.md +150 -183
  2. package/dist/backend.d.ts +151 -0
  3. package/dist/backend.js +3 -0
  4. package/dist/backend.js.map +1 -0
  5. package/dist/bridge.d.ts +56 -0
  6. package/dist/bridge.js +507 -0
  7. package/dist/bridge.js.map +1 -0
  8. package/dist/errors.d.ts +81 -43
  9. package/dist/errors.js +98 -52
  10. package/dist/errors.js.map +1 -1
  11. package/dist/index.d.ts +10 -10
  12. package/dist/index.js +25 -52
  13. package/dist/index.js.map +1 -1
  14. package/dist/mac/accounts.d.ts +7 -2
  15. package/dist/mac/accounts.js +23 -6
  16. package/dist/mac/accounts.js.map +1 -1
  17. package/dist/mac/attachments.d.ts +5 -25
  18. package/dist/mac/attachments.js +40 -99
  19. package/dist/mac/attachments.js.map +1 -1
  20. package/dist/mac/bounces.d.ts +12 -27
  21. package/dist/mac/bounces.js +95 -112
  22. package/dist/mac/bounces.js.map +1 -1
  23. package/dist/mac/cleanup.d.ts +11 -25
  24. package/dist/mac/cleanup.js +50 -76
  25. package/dist/mac/cleanup.js.map +1 -1
  26. package/dist/mac/drafts.d.ts +13 -34
  27. package/dist/mac/drafts.js +95 -169
  28. package/dist/mac/drafts.js.map +1 -1
  29. package/dist/mac/folders.d.ts +10 -21
  30. package/dist/mac/folders.js +33 -47
  31. package/dist/mac/folders.js.map +1 -1
  32. package/dist/mac/index.d.ts +2 -22
  33. package/dist/mac/index.js +19 -81
  34. package/dist/mac/index.js.map +1 -1
  35. package/dist/mac/profile.d.ts +13 -0
  36. package/dist/mac/profile.js +149 -0
  37. package/dist/mac/profile.js.map +1 -0
  38. package/dist/mac/read.d.ts +18 -38
  39. package/dist/mac/read.js +154 -210
  40. package/dist/mac/read.js.map +1 -1
  41. package/dist/mac/run.d.ts +35 -39
  42. package/dist/mac/run.js +97 -102
  43. package/dist/mac/run.js.map +1 -1
  44. package/dist/mac/scripts.d.ts +78 -86
  45. package/dist/mac/scripts.js +125 -115
  46. package/dist/mac/scripts.js.map +1 -1
  47. package/dist/mac/send.d.ts +10 -20
  48. package/dist/mac/send.js +64 -86
  49. package/dist/mac/send.js.map +1 -1
  50. package/dist/mac/signatures.d.ts +2 -2
  51. package/dist/mac/signatures.js +9 -11
  52. package/dist/mac/signatures.js.map +1 -1
  53. package/dist/mac/templates.d.ts +14 -26
  54. package/dist/mac/templates.js +75 -113
  55. package/dist/mac/templates.js.map +1 -1
  56. package/dist/mail.d.ts +77 -45
  57. package/dist/mail.js +166 -73
  58. package/dist/mail.js.map +1 -1
  59. package/dist/runtime.d.ts +76 -43
  60. package/dist/runtime.js +103 -48
  61. package/dist/runtime.js.map +1 -1
  62. package/dist/shared/args.d.ts +48 -0
  63. package/dist/shared/args.js +216 -0
  64. package/dist/shared/args.js.map +1 -0
  65. package/dist/shared/attachmentMatch.d.ts +28 -16
  66. package/dist/shared/attachmentMatch.js +60 -22
  67. package/dist/shared/attachmentMatch.js.map +1 -1
  68. package/dist/shared/bounceReport.d.ts +11 -0
  69. package/dist/shared/bounceReport.js +45 -0
  70. package/dist/shared/bounceReport.js.map +1 -0
  71. package/dist/shared/bounceRules.d.ts +38 -10
  72. package/dist/shared/bounceRules.js +50 -32
  73. package/dist/shared/bounceRules.js.map +1 -1
  74. package/dist/shared/exec.d.ts +21 -0
  75. package/dist/shared/exec.js +47 -0
  76. package/dist/shared/exec.js.map +1 -0
  77. package/dist/shared/json.d.ts +12 -6
  78. package/dist/shared/json.js +29 -23
  79. package/dist/shared/json.js.map +1 -1
  80. package/dist/shared/locate.d.ts +39 -0
  81. package/dist/shared/locate.js +129 -0
  82. package/dist/shared/locate.js.map +1 -0
  83. package/dist/shared/replyBody.d.ts +42 -32
  84. package/dist/shared/replyBody.js +84 -71
  85. package/dist/shared/replyBody.js.map +1 -1
  86. package/dist/templateBody.d.ts +63 -0
  87. package/dist/{outlookTemplateSections.js → templateBody.js} +72 -72
  88. package/dist/templateBody.js.map +1 -0
  89. package/dist/types.d.ts +360 -167
  90. package/dist/types.js +8 -9
  91. package/dist/types.js.map +1 -1
  92. package/dist/windows/accounts.d.ts +7 -12
  93. package/dist/windows/accounts.js +19 -34
  94. package/dist/windows/accounts.js.map +1 -1
  95. package/dist/windows/attachments.d.ts +9 -24
  96. package/dist/windows/attachments.js +94 -119
  97. package/dist/windows/attachments.js.map +1 -1
  98. package/dist/windows/bounces.d.ts +13 -26
  99. package/dist/windows/bounces.js +168 -200
  100. package/dist/windows/bounces.js.map +1 -1
  101. package/dist/windows/cleanup.d.ts +19 -23
  102. package/dist/windows/cleanup.js +92 -111
  103. package/dist/windows/cleanup.js.map +1 -1
  104. package/dist/windows/drafts.d.ts +16 -35
  105. package/dist/windows/drafts.js +167 -253
  106. package/dist/windows/drafts.js.map +1 -1
  107. package/dist/windows/folders.d.ts +8 -13
  108. package/dist/windows/folders.js +44 -52
  109. package/dist/windows/folders.js.map +1 -1
  110. package/dist/windows/index.d.ts +2 -27
  111. package/dist/windows/index.js +11 -66
  112. package/dist/windows/index.js.map +1 -1
  113. package/dist/windows/read.d.ts +24 -60
  114. package/dist/windows/read.js +261 -306
  115. package/dist/windows/read.js.map +1 -1
  116. package/dist/windows/run.d.ts +39 -39
  117. package/dist/windows/run.js +151 -111
  118. package/dist/windows/run.js.map +1 -1
  119. package/dist/windows/scripts.d.ts +65 -55
  120. package/dist/windows/scripts.js +109 -85
  121. package/dist/windows/scripts.js.map +1 -1
  122. package/dist/windows/send.d.ts +6 -11
  123. package/dist/windows/send.js +68 -88
  124. package/dist/windows/send.js.map +1 -1
  125. package/dist/windows/signatures.d.ts +4 -10
  126. package/dist/windows/signatures.js +30 -37
  127. package/dist/windows/signatures.js.map +1 -1
  128. package/dist/windows/templates.d.ts +12 -18
  129. package/dist/windows/templates.js +122 -149
  130. package/dist/windows/templates.js.map +1 -1
  131. package/package.json +4 -3
  132. package/dist/OutlookService.d.ts +0 -43
  133. package/dist/OutlookService.js +0 -137
  134. package/dist/OutlookService.js.map +0 -1
  135. package/dist/outlookTemplateSections.d.ts +0 -62
  136. package/dist/outlookTemplateSections.js.map +0 -1
  137. package/dist/shared/capabilities.d.ts +0 -3
  138. package/dist/shared/capabilities.js +0 -9
  139. package/dist/shared/capabilities.js.map +0 -1
package/dist/mac/read.js CHANGED
@@ -8,49 +8,31 @@ exports.openOutlookEmail = openOutlookEmail;
8
8
  // Reading mail on macOS: one folder, one item, a whole Inbox tree, or whatever
9
9
  // is selected in the running Outlook.
10
10
  //
11
- // Every reader here is two passes. Pass 1 indexes a folder with bulk property
12
- // reads (one Apple event each); pass 2 fetches the expensive fields — body,
11
+ // Every reader is two passes. Pass 1 indexes a folder with bulk property reads
12
+ // (one Apple event each); pass 2 fetches the expensive fields — body,
13
13
  // attachments, sender — only for the messages that survived. Reading
14
14
  // per-message in a loop costs an event per property and is unusably slow on a
15
15
  // real mailbox, which is the whole reason for the shape.
16
16
  const run_1 = require("./run");
17
17
  const scripts_1 = require("./scripts");
18
- const mail_1 = require("../mail");
19
18
  const errors_1 = require("../errors");
20
- /** How much of a body readInboxEmails previews, matching the Windows reader. */
21
- const PREVIEW_CHARS = 600;
19
+ const mail_1 = require("../mail");
22
20
  /**
23
- * Read recent messages for the given account, newest first.
24
- *
25
- * `entryId` here is Outlook for Mac's small integer message id (e.g. "779"), not
26
- * the MAPI EntryID string Windows returns. The two are not interchangeable, so
27
- * don't persist one and look it up on the other platform.
21
+ * Recent mail from the Inbox root or one folder, newest first. Entry ids here
22
+ * are Outlook for Mac's integer message ids, not Windows EntryIDs.
28
23
  */
29
- async function readInboxEmails(emailAccount, daysBack = 60, limit = 50, folder) {
30
- const days = Math.max(0, Math.floor(daysBack));
31
- const cap = Math.max(0, Math.floor(limit));
32
- if (cap === 0)
33
- return [];
34
- const ref = folder ? (0, mail_1.mailFolderRef)(folder) : { rootId: 6, rootLabel: 'Inbox', segments: [] };
35
- // A folder argument that trims away to nothing ("\\", " ") would otherwise
36
- // read the Inbox root and look like it had scoped — the exact silent
37
- // mis-scoping this parameter exists to prevent. Mirrors the Windows check.
38
- if (folder && folder.trim() && ref.segments.length === 0 && ref.rootId === 6
39
- && folder.trim().toLowerCase() !== 'inbox') {
40
- throw new errors_1.NotFoundError('folder', `Folder '${folder}' does not name a folder under the Inbox.`);
41
- }
42
- const resolveScope = (0, scripts_1.mailScopeSnippet)(ref, folder || '');
43
- const folderPath = (0, scripts_1.macFolderPath)(emailAccount, ref.rootLabel, ref.segments);
44
- const isOutgoing = (0, mail_1.isOutgoingRoot)(ref.rootId);
45
- // Pass 1 — index the folder. Folder order isn't documented, so sort here
46
- // rather than trusting Outlook to hand back newest-first.
47
- const indexScript = `tell application "Microsoft Outlook"
48
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
49
- ${resolveScope}
50
- set cutoff to (current date) - (${days} * days)
24
+ async function readInboxEmails(request) {
25
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
26
+ const folderPath = (0, scripts_1.macFolderPath)(request.account, request.folder.rootLabel, request.folder.segments);
27
+ const outgoing = (0, mail_1.isOutgoingRoot)(request.folder.rootId);
28
+ // Pass 1 — index the folder. Its order isn't documented, so it is sorted here.
29
+ const index = (await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
30
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
31
+ ${(0, scripts_1.mailScopeSnippet)(acct, request.folder, request.folderLabel)}
32
+ set cutoff to (current date) - (${(0, run_1.asInt)(request.daysBack)} * days)
51
33
  set idList to id of every message of scopeFolder
52
34
  try
53
- set timeList to ${(0, scripts_1.dateProperty)(ref.rootId)} of every message of scopeFolder
35
+ set timeList to ${(0, scripts_1.dateProperty)(request.folder.rootId)} of every message of scopeFolder
54
36
  on error
55
37
  set timeList to {}
56
38
  end try
@@ -59,16 +41,14 @@ ${resolveScope}
59
41
  repeat with i from 1 to (count of idList)
60
42
  set d to missing value
61
43
  if hasTimes then set d to item i of timeList
62
- -- An item carrying no timestamp of its own (an unsent draft filed into a
63
- -- mail folder) is skipped rather than crashing the walk, matching what the
64
- -- Windows Restrict on the same property does with it.
44
+ -- An item with no timestamp of its own (an unsent draft filed into a
45
+ -- mail folder) is skipped, as the Windows date filter skips it.
65
46
  if d is not missing value and d is greater than or equal to cutoff then
66
47
  set out to out & (item i of idList as string) & tab & my isoDate(d) & linefeed
67
48
  end if
68
49
  end repeat
69
50
  return out
70
- end tell`;
71
- const index = (await (0, run_1.runOsaScript)(indexScript, 60000))
51
+ end tell`, 'standard'))
72
52
  .split('\n')
73
53
  .map(line => line.trim())
74
54
  .filter(Boolean)
@@ -76,59 +56,54 @@ end tell`;
76
56
  const [id, receivedTime] = line.split('\t');
77
57
  return { id, receivedTime: receivedTime || '' };
78
58
  });
79
- // 'yyyy-MM-dd HH:mm' is lexicographically ordered, so plain string compare sorts it.
59
+ // 'yyyy-MM-dd HH:mm' sorts correctly as a string.
80
60
  index.sort((a, b) => b.receivedTime.localeCompare(a.receivedTime));
81
- const chosen = index.slice(0, cap);
61
+ const chosen = index.slice(0, request.limit);
82
62
  if (chosen.length === 0)
83
63
  return [];
84
- // Pass 2 — the expensive reads, only for messages we keep.
85
- const detailScript = `tell application "Microsoft Outlook"
86
- set wanted to {${chosen.map(c => c.id).join(', ')}}
64
+ // Pass 2 — the expensive reads, only for the messages kept.
65
+ const preview = request.previewChars > 0
66
+ ? ` set bodyText to ""
67
+ try
68
+ set bodyText to (plain text content of theMsg) as string
69
+ end try
70
+ if (length of bodyText) > ${(0, run_1.asInt)(request.previewChars)} then set bodyText to text 1 thru ${(0, run_1.asInt)(request.previewChars)} of bodyText`
71
+ : ' set bodyText to ""';
72
+ const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
87
73
  set out to ""
88
- repeat with k from 1 to (count of wanted)
74
+ repeat with theId in ${(0, run_1.asIdList)(chosen.map(c => c.id))}
89
75
  set theMsg to missing value
90
76
  try
91
- set theMsg to message id (item k of wanted)
77
+ set theMsg to message id theId
92
78
  end try
93
79
  if theMsg is not missing value then
94
80
  set subj to ""
95
81
  try
96
82
  set subj to (subject of theMsg) as string
97
83
  end try
98
- ${isOutgoing ? (0, scripts_1.firstRecipientSnippet)('theMsg', ' ') : (0, scripts_1.senderSnippet)('theMsg', ' ')}
99
- set bodyText to ""
100
- try
101
- set bodyText to (plain text content of theMsg) as string
102
- end try
103
- if (length of bodyText) > ${PREVIEW_CHARS} then set bodyText to text 1 thru ${PREVIEW_CHARS} of bodyText
84
+ ${outgoing ? (0, scripts_1.firstRecipientSnippet)('theMsg', ' ') : (0, scripts_1.senderSnippet)('theMsg', ' ')}
85
+ ${preview}
104
86
  set attNames to {}
105
87
  try
106
88
  set attNames to name of every attachment of theMsg
107
89
  end try
108
- set out to out & ${(0, run_1.asRow)([
109
- '(id of theMsg as string)',
110
- 'subj',
111
- 'sndName',
112
- 'sndAddr',
113
- 'bodyText',
114
- 'my sanitizeList(attNames)',
115
- ])}
90
+ set out to out & ${(0, run_1.asRow)(['(id of theMsg as string)', 'subj', 'sndName', 'sndAddr', 'bodyText', 'my sanitizeList(attNames)'])}
116
91
  end if
117
92
  end repeat
118
93
  return out
119
- end tell`;
120
- const byId = new Map(chosen.map(c => [c.id, c.receivedTime]));
121
- return (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(detailScript, 120000)).map(record => {
94
+ end tell`, 'standard');
95
+ const receivedById = new Map(chosen.map(c => [c.id, c.receivedTime]));
96
+ return (0, run_1.splitRecords)(raw).map(record => {
122
97
  const parts = (0, run_1.splitFields)(record);
123
98
  const id = (0, run_1.field)(parts, 0);
124
99
  const attachmentNames = (0, run_1.splitList)((0, run_1.field)(parts, 5));
125
100
  return {
126
101
  entryId: id,
127
- storeId: '', // macOS AppleScript has no StoreID equivalent
102
+ storeId: '',
128
103
  subject: (0, run_1.field)(parts, 1).trim(),
129
104
  senderName: (0, run_1.field)(parts, 2),
130
105
  senderEmail: (0, run_1.field)(parts, 3),
131
- receivedTime: byId.get(id) || '',
106
+ receivedTime: receivedById.get(id) || '',
132
107
  bodyPreview: (0, run_1.field)(parts, 4),
133
108
  attachmentNames,
134
109
  attachmentCount: attachmentNames.length,
@@ -137,172 +112,160 @@ end tell`;
137
112
  });
138
113
  }
139
114
  /**
140
- * Read one email's full plain-text body by message id.
141
- *
142
- * `storeId` is accepted for signature parity and ignored: macOS has no StoreID,
143
- * and `message id N` resolves against the application rather than one folder, so
144
- * the message is found wherever it currently sits — including a subfolder.
145
- *
146
- * Uses `plain text content`, matching the Windows reader's use of `.Body`: the
147
- * same tradeoff applies, so an HTML table's rows flatten and tabular figures are
148
- * better read from an attachment.
115
+ * One email's full plain-text body. `storeId` has no macOS meaning: `message id
116
+ * N` resolves against the application, wherever the message sits.
149
117
  */
150
- async function readEmailBody(entryId, _storeId, maxChars = 8000, includeQuoted = false) {
151
- const id = (0, scripts_1.macMessageId)(entryId);
152
- const script = `tell application "Microsoft Outlook"
118
+ async function readEmailBody(email) {
119
+ const id = (0, scripts_1.macMessageId)(email.entryId);
120
+ const parts = (0, run_1.summaryFields)(await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
153
121
  ${(0, scripts_1.messageLookupSnippet)(id)}
154
122
  ${(0, scripts_1.messageDetailSnippet)(true)}
155
123
  return ${(0, run_1.asRow)((0, scripts_1.messageDetailFields)(true))}
156
- end tell`;
157
- // The body is emitted LAST so a stray separator in earlier fields can't shift it.
158
- const parts = (0, run_1.summaryFields)(await (0, run_1.runOsaScript)(script, 60000));
159
- const attachmentNames = (0, run_1.splitList)((0, run_1.field)(parts, scripts_1.MessageDetail.attachmentNames));
160
- const { body, quoted, separator } = (0, mail_1.splitQuotedOriginal)((0, run_1.field)(parts, scripts_1.MessageDetail.body));
161
- // The quoted thread is context, never the priced content, so it is capped
162
- // harder than the reply itself — matching the Windows reader.
163
- const quotedCap = Math.min(maxChars, 4000);
124
+ end tell`, 'quick'));
164
125
  return {
165
126
  entryId: (0, run_1.field)(parts, scripts_1.MessageDetail.id) || id,
166
127
  subject: (0, run_1.field)(parts, scripts_1.MessageDetail.subject).trim(),
167
128
  senderName: (0, run_1.field)(parts, scripts_1.MessageDetail.senderName),
168
129
  senderEmail: (0, run_1.field)(parts, scripts_1.MessageDetail.senderEmail),
169
130
  receivedTime: (0, run_1.field)(parts, scripts_1.MessageDetail.receivedTime),
170
- body: body.length > maxChars ? body.slice(0, maxChars) : body,
171
- truncated: body.length > maxChars,
172
- bodyLength: body.length,
173
- quoteSeparator: separator,
174
- quotedLength: quoted.length,
175
- quotedOriginal: includeQuoted ? quoted.slice(0, quotedCap) : '',
176
- attachmentNames,
177
- attachmentCount: attachmentNames.length,
131
+ body: (0, run_1.field)(parts, scripts_1.MessageDetail.body),
132
+ attachmentNames: (0, run_1.splitList)((0, run_1.field)(parts, scripts_1.MessageDetail.attachmentNames)),
178
133
  };
179
134
  }
180
135
  /**
181
- * Translate a Restrict-style `like` pattern to a regex.
136
+ * Walk every folder under the Inbox for the mail matching the request.
182
137
  *
183
- * Windows hands `subjectLike` to Outlook's server-side Restrict; AppleScript has
184
- * no equivalent, so the same pattern is applied here instead. `%` and `*` are
185
- * the any-run wildcards, `_` and `?` match one character, and the match is
186
- * anchored because that is what SQL `like` means.
138
+ * The filtering happens here rather than in Outlook: there is no AppleScript
139
+ * counterpart to COM's server-side `Items.Restrict`, so each folder is indexed in
140
+ * bulk reads and the subject and date tests run on the index. The results match
141
+ * Windows; the cost doesn't, and a wide window over a big tree is heavier here.
187
142
  */
188
- function likePattern(pattern) {
189
- let source = '';
190
- for (const ch of pattern) {
191
- if (ch === '%' || ch === '*')
192
- source += '.*';
193
- else if (ch === '_' || ch === '?')
194
- source += '.';
195
- else
196
- source += ch.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
197
- }
198
- return new RegExp(`^${source}$`, 'i');
199
- }
200
- /**
201
- * Walk every folder under the Inbox (recursively) for one account and return the
202
- * emails matching `filter` — full body included, attachments listed by name but
203
- * not saved.
204
- *
205
- * The filtering happens here rather than in Outlook: `Items.Restrict` is a COM
206
- * facility with no AppleScript counterpart, so the folder walk indexes each
207
- * folder in two bulk reads and the subject/date tests run on the index. The
208
- * observable contract is the same; the cost profile is not, and a `daysBack` of
209
- * 0 over a large mailbox tree is correspondingly heavier here.
210
- *
211
- * `subjectPattern` is applied case-insensitively regardless of the RegExp's own
212
- * flags, matching PowerShell's `-match`.
213
- */
214
- async function searchInboxByFilter(emailAccount, filter = {}, daysBack = 0) {
215
- const days = Math.max(0, Math.floor(daysBack));
143
+ async function searchInboxByFilter(request) {
144
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
145
+ // AppleScript reaches a child folder by name, so a path entry narrows to its leaf.
146
+ const asNameList = (list) => `{${list.map(mail_1.folderLeafName).filter(Boolean).map(run_1.asString).join(', ')}}`;
147
+ const rootInScope = request.includeFolders.length === 0 ? 'true' : 'false';
148
+ // Sent, Drafts, Deleted and Junk hang UNDER the Inbox on an IMAP profile, so
149
+ // their ids are collected first and the walk never descends into them — by
150
+ // the profile's own id where it records one, through the account otherwise.
151
+ const skipIds = ['sent items', 'deleted items', 'drafts', 'junk mail']
152
+ .map(term => {
153
+ const id = acct.folderIds?.[term];
154
+ return id !== undefined
155
+ ? ` set end of skipIds to ${id}`
156
+ : ` try
157
+ set end of skipIds to (id of (${term} of targetAcct))
158
+ end try`;
159
+ })
160
+ .join('\n');
216
161
  // Pass 1 — index every folder under the Inbox: path, id, subject, received.
217
- const indexScript = `on scanFolder(theFolder, prefix, cutoff, useCutoff)
162
+ const indexed = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(`on scanFolder(theFolder, prefix, cutoff, skipIds, skipNames, onlyNames, inScope)
218
163
  set out to ""
164
+ set idList to {}
165
+ set subjList to {}
166
+ set timeList to {}
167
+ -- A folder the walk only passes through is never read: the bulk reads are
168
+ -- the expensive part.
169
+ if inScope then
170
+ tell application "Microsoft Outlook"
171
+ set idList to id of every message of theFolder
172
+ set subjList to subject of every message of theFolder
173
+ try
174
+ set timeList to time received of every message of theFolder
175
+ on error
176
+ set timeList to {}
177
+ end try
178
+ end tell
179
+ end if
219
180
  tell application "Microsoft Outlook"
220
- set idList to id of every message of theFolder
221
- set subjList to subject of every message of theFolder
222
- try
223
- set timeList to time received of every message of theFolder
224
- on error
225
- set timeList to {}
226
- end try
227
181
  set subs to mail folders of theFolder
228
182
  end tell
229
183
  set hasTimes to ((count of timeList) is (count of idList))
230
184
  repeat with i from 1 to (count of idList)
231
185
  set d to missing value
232
186
  if hasTimes then set d to item i of timeList
233
- set keep to true
234
- if d is missing value then
235
- -- A folder whose items carry no readable receive time can only be
236
- -- included when the caller isn't bounding by date; silently dropping
237
- -- it would look exactly like an empty folder.
238
- set keep to not useCutoff
239
- else if useCutoff and d is less than cutoff then
240
- set keep to false
241
- end if
242
- if keep then
243
- set out to out & ${(0, run_1.asRow)([
244
- 'prefix',
245
- '(item i of idList as string)',
246
- '(item i of subjList)',
247
- 'my isoDate(d)',
248
- ])}
187
+ -- An item with no readable receive time is kept whatever the window
188
+ -- says; dropping it would make a folder of them look empty.
189
+ if d is missing value or d is not less than cutoff then
190
+ set out to out & ${(0, run_1.asRow)(['prefix', '(item i of idList as string)', '(item i of subjList)', 'my isoDate(d)'])}
249
191
  end if
250
192
  end repeat
251
193
  repeat with f in subs
252
- set childName to ""
194
+ set skipThis to false
253
195
  try
254
- set childName to (name of f) as string
196
+ if skipIds contains (id of f) then set skipThis to true
255
197
  end try
256
- set out to out & my scanFolder(f, prefix & ${run_1.AS_LIST_SEP} & childName, cutoff, useCutoff)
198
+ try
199
+ if skipNames contains ((name of f) as string) then set skipThis to true
200
+ end try
201
+ if not skipThis then
202
+ set childName to ""
203
+ try
204
+ set childName to (name of f) as string
205
+ end try
206
+ set childScope to (count of onlyNames) is 0
207
+ try
208
+ if onlyNames contains childName then set childScope to true
209
+ end try
210
+ set out to out & my scanFolder(f, prefix & ${run_1.AS_LIST_SEP} & childName, cutoff, skipIds, skipNames, onlyNames, childScope)
211
+ end if
257
212
  end repeat
258
213
  return out
259
214
  end scanFolder
260
215
 
261
216
  tell application "Microsoft Outlook"
262
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
263
- set rootInbox to inbox of targetAcct
217
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
218
+ ${(0, scripts_1.rootFolderSnippet)(acct, 'inbox', 'rootInbox')}
264
219
  set rootName to (name of rootInbox) as string
220
+ set skipIds to {}
221
+ ${skipIds}
222
+ set skipNames to ${asNameList(request.excludeFolders)}
223
+ set onlyNames to ${asNameList(request.includeFolders)}
265
224
  end tell
266
- set cutoff to (current date) - (${days} * days)
267
- return my scanFolder(rootInbox, rootName, cutoff, ${days > 0 ? 'true' : 'false'})`;
268
- const likeRe = filter.subjectLike ? likePattern(filter.subjectLike) : null;
269
- // PowerShell's -match is case-insensitive by default, so the pattern is
270
- // rebuilt with `i` regardless of the flags the caller's RegExp carries.
271
- const patternRe = filter.subjectPattern
272
- ? new RegExp(filter.subjectPattern.source, 'i')
273
- : null;
274
- const candidates = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(indexScript, 300000))
225
+ set cutoff to (current date) - (${(0, run_1.asInt)(request.daysBack)} * days)
226
+ return my scanFolder(rootInbox, rootName, cutoff, skipIds, skipNames, onlyNames, ${rootInScope})`, 'scan'));
227
+ const subjectFiltered = !!(request.subjectLike || request.subjectPattern || request.excludeReplies);
228
+ const likeRe = request.subjectLike ? new RegExp((0, mail_1.subjectGlobSource)(request.subjectLike), 'i') : null;
229
+ // PowerShell's -match is case-insensitive, so the Windows test is too.
230
+ const patternRe = request.subjectPattern ? new RegExp(request.subjectPattern.source, 'i') : null;
231
+ const candidates = indexed
275
232
  .map(record => {
276
233
  const parts = (0, run_1.splitFields)(record);
277
234
  const segments = (0, run_1.splitList)((0, run_1.field)(parts, 0));
278
235
  return {
279
- folderPath: (0, scripts_1.macFolderPath)(emailAccount, segments[0] || 'Inbox', segments.slice(1)),
236
+ folderPath: (0, scripts_1.macFolderPath)(request.account, segments[0] || 'Inbox', segments.slice(1)),
280
237
  id: (0, run_1.field)(parts, 1),
281
238
  subject: (0, run_1.field)(parts, 2).trim(),
282
239
  receivedTime: (0, run_1.field)(parts, 3),
283
240
  };
284
241
  })
285
242
  .filter(candidate => {
286
- if (!candidate.subject)
243
+ if (subjectFiltered && !candidate.subject)
287
244
  return false;
288
245
  if (likeRe && !likeRe.test(candidate.subject))
289
246
  return false;
290
247
  if (patternRe && !patternRe.test(candidate.subject))
291
248
  return false;
292
- if (filter.excludeReplies && /^(re|fwd?)\s*:/i.test(candidate.subject))
249
+ if (request.excludeReplies && mail_1.REPLY_PREFIX.test(candidate.subject))
293
250
  return false;
294
251
  return true;
295
252
  });
296
253
  if (candidates.length === 0)
297
254
  return [];
298
- // Pass 2 — bodies, senders and attachment names for the survivors only.
299
- const detailScript = `tell application "Microsoft Outlook"
300
- set wanted to {${candidates.map(c => c.id).join(', ')}}
255
+ // Pass 2 — senders, attachment names and (when asked) bodies, for the survivors only.
256
+ const body = request.includeBody
257
+ ? ` set bodyText to ""
258
+ try
259
+ set bodyText to (plain text content of theMsg) as string
260
+ end try`
261
+ : ' set bodyText to ""';
262
+ const details = new Map();
263
+ const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
301
264
  set out to ""
302
- repeat with k from 1 to (count of wanted)
265
+ repeat with theId in ${(0, run_1.asIdList)(candidates.map(c => c.id))}
303
266
  set theMsg to missing value
304
267
  try
305
- set theMsg to message id (item k of wanted)
268
+ set theMsg to message id theId
306
269
  end try
307
270
  if theMsg is not missing value then
308
271
  ${(0, scripts_1.senderSnippet)('theMsg', ' ')}
@@ -310,23 +273,13 @@ ${(0, scripts_1.senderSnippet)('theMsg', ' ')}
310
273
  try
311
274
  set attNames to name of every attachment of theMsg
312
275
  end try
313
- set bodyText to ""
314
- try
315
- set bodyText to (plain text content of theMsg) as string
316
- end try
317
- set out to out & ${(0, run_1.asRow)([
318
- '(id of theMsg as string)',
319
- 'sndName',
320
- 'sndAddr',
321
- 'my sanitizeList(attNames)',
322
- 'bodyText',
323
- ])}
276
+ ${body}
277
+ set out to out & ${(0, run_1.asRow)(['(id of theMsg as string)', 'sndName', 'sndAddr', 'my sanitizeList(attNames)', 'bodyText'])}
324
278
  end if
325
279
  end repeat
326
280
  return out
327
- end tell`;
328
- const details = new Map();
329
- for (const record of (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(detailScript, 300000))) {
281
+ end tell`, 'scan');
282
+ for (const record of (0, run_1.splitRecords)(raw)) {
330
283
  const parts = (0, run_1.splitFields)(record);
331
284
  details.set((0, run_1.field)(parts, 0), {
332
285
  senderName: (0, run_1.field)(parts, 1),
@@ -340,13 +293,12 @@ end tell`;
340
293
  const detail = details.get(candidate.id);
341
294
  if (!detail)
342
295
  continue;
343
- // requireAttachment can only be answered once the attachment names are in
344
- // hand, so it filters here rather than during the index pass.
345
- if (filter.requireAttachment && detail.attachmentNames.length === 0)
296
+ // Attachment names only arrive with the details, so this test waits for them.
297
+ if (request.requireAttachment && detail.attachmentNames.length === 0)
346
298
  continue;
347
299
  matches.push({
348
300
  entryId: candidate.id,
349
- storeId: '', // macOS AppleScript has no StoreID equivalent
301
+ storeId: '',
350
302
  subject: candidate.subject,
351
303
  senderName: detail.senderName,
352
304
  senderEmail: detail.senderEmail,
@@ -359,31 +311,26 @@ end tell`;
359
311
  return matches;
360
312
  }
361
313
  /**
362
- * Read the email currently selected (or open) in Outlook — full body,
363
- * attachments listed by name but not saved.
364
- *
365
- * `current messages` covers both cases the Windows reader handles separately
366
- * (an explorer selection and an open item), so there is no second lookup here.
314
+ * The email currently selected — or open — in Outlook. `current messages`
315
+ * covers both cases the Windows reader handles separately.
367
316
  */
368
317
  async function readSelectedEmail() {
369
- const script = `tell application "Microsoft Outlook"
318
+ const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
370
319
  set sel to {}
371
320
  try
372
321
  set sel to current messages
373
322
  end try
374
- if (count of sel) is 0 then error "No email is selected in Outlook. Open Outlook, select (or open) an email, then try again."
323
+ if (count of sel) is 0 then error ${(0, run_1.asString)(`${(0, errors_1.failureTag)('NOT_FOUND', 'email')}No email is selected in Outlook. Select or open an email, then try again.`)}
375
324
  set theMsg to item 1 of sel
376
325
  ${(0, scripts_1.messageDetailSnippet)(true)}
377
326
  return ${(0, run_1.asRow)((0, scripts_1.messageDetailFields)(true))}
378
- end tell`;
379
- const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 30000));
380
- if (records.length === 0) {
381
- throw new errors_1.NotFoundError('email', 'Failed to read the selected Outlook email.');
382
- }
327
+ end tell`, 'quick'));
328
+ if (records.length === 0)
329
+ throw new errors_1.NotFoundError('email', 'Outlook reported no selected email.');
383
330
  const parts = (0, run_1.splitFields)(records[0]);
384
331
  return {
385
332
  entryId: (0, run_1.field)(parts, scripts_1.MessageDetail.id),
386
- storeId: '', // macOS AppleScript has no StoreID equivalent
333
+ storeId: '',
387
334
  subject: (0, run_1.field)(parts, scripts_1.MessageDetail.subject).trim(),
388
335
  senderName: (0, run_1.field)(parts, scripts_1.MessageDetail.senderName),
389
336
  senderEmail: (0, run_1.field)(parts, scripts_1.MessageDetail.senderEmail),
@@ -392,17 +339,14 @@ end tell`;
392
339
  attachmentNames: (0, run_1.splitList)((0, run_1.field)(parts, scripts_1.MessageDetail.attachmentNames)),
393
340
  };
394
341
  }
395
- /** Open an email in Outlook by its message id, and bring Outlook forward.
396
- * `_storeId` is accepted for parity with Windows and ignored — macOS
397
- * AppleScript has no StoreID (see `readEmailBody`). */
398
- async function openOutlookEmail(entryId, _storeId) {
399
- const id = (0, scripts_1.macMessageId)(entryId);
400
- const script = `
342
+ /** Open an email in Outlook and bring Outlook forward. */
343
+ async function openOutlookEmail(email) {
344
+ const id = (0, scripts_1.macMessageId)(email.entryId);
345
+ await (0, run_1.runOsaScript)(`
401
346
  tell application "Microsoft Outlook"
402
347
  ${(0, scripts_1.messageLookupSnippet)(id)}
403
348
  open theMsg
404
349
  activate
405
- end tell`;
406
- await (0, run_1.runOsaScript)(script, 30000);
350
+ end tell`, 'quick');
407
351
  }
408
352
  //# sourceMappingURL=read.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/mac/read.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/mac/read.ts"],"names":[],"mappings":"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","sourcesContent":["// Reading mail on macOS: one folder, one item, a whole Inbox tree, or whatever\n// is selected in the running Outlook.\n//\n// Every reader is two passes. Pass 1 indexes a folder with bulk property reads\n// (one Apple event each); pass 2 fetches the expensive fields — body,\n// attachments, sender — only for the messages that survived. Reading\n// per-message in a loop costs an event per property and is unusably slow on a\n// real mailbox, which is the whole reason for the shape.\nimport {\n AS_LIST_SEP,\n asIdList,\n asInt,\n asRow,\n asString,\n field,\n runOsaScript,\n splitFields,\n splitList,\n splitRecords,\n summaryFields\n} from './run';\nimport {\n accountLookupSnippet,\n dateProperty,\n firstRecipientSnippet,\n macFolderPath,\n macMessageId,\n mailScopeSnippet,\n MessageDetail,\n messageDetailFields,\n messageDetailSnippet,\n messageLookupSnippet,\n resolveMacAccount,\n rootFolderSnippet,\n senderSnippet,\n} from './scripts';\nimport { failureTag, NotFoundError } from '../errors';\nimport { folderLeafName, isOutgoingRoot, REPLY_PREFIX, subjectGlobSource } from '../mail';\nimport type { RawEmail, ReadInboxRequest, SearchRequest } from '../backend';\nimport type { EmailLocator, InboxEmail, InboxSearchMatch, SelectedEmail } from '../types';\n\n/**\n * Recent mail from the Inbox root or one folder, newest first. Entry ids here\n * are Outlook for Mac's integer message ids, not Windows EntryIDs.\n */\nexport async function readInboxEmails(request: ReadInboxRequest): Promise<InboxEmail[]> {\n const acct = await resolveMacAccount(request.account);\n const folderPath = macFolderPath(request.account, request.folder.rootLabel, request.folder.segments);\n const outgoing = isOutgoingRoot(request.folder.rootId);\n\n // Pass 1 — index the folder. Its order isn't documented, so it is sorted here.\n const index = (await runOsaScript(`tell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${mailScopeSnippet(acct, request.folder, request.folderLabel)}\n set cutoff to (current date) - (${asInt(request.daysBack)} * days)\n set idList to id of every message of scopeFolder\n try\n set timeList to ${dateProperty(request.folder.rootId)} of every message of scopeFolder\n on error\n set timeList to {}\n end try\n set hasTimes to ((count of timeList) is (count of idList))\n set out to \"\"\n repeat with i from 1 to (count of idList)\n set d to missing value\n if hasTimes then set d to item i of timeList\n -- An item with no timestamp of its own (an unsent draft filed into a\n -- mail folder) is skipped, as the Windows date filter skips it.\n if d is not missing value and d is greater than or equal to cutoff then\n set out to out & (item i of idList as string) & tab & my isoDate(d) & linefeed\n end if\n end repeat\n return out\nend tell`, 'standard'))\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => {\n const [id, receivedTime] = line.split('\\t');\n return {id, receivedTime: receivedTime || ''};\n });\n // 'yyyy-MM-dd HH:mm' sorts correctly as a string.\n index.sort((a, b) => b.receivedTime.localeCompare(a.receivedTime));\n const chosen = index.slice(0, request.limit);\n if (chosen.length === 0) return [];\n\n // Pass 2 — the expensive reads, only for the messages kept.\n const preview = request.previewChars > 0\n ? ` set bodyText to \"\"\n try\n set bodyText to (plain text content of theMsg) as string\n end try\n if (length of bodyText) > ${asInt(request.previewChars)} then set bodyText to text 1 thru ${asInt(request.previewChars)} of bodyText`\n : ' set bodyText to \"\"';\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n set out to \"\"\n repeat with theId in ${asIdList(chosen.map(c => c.id))}\n set theMsg to missing value\n try\n set theMsg to message id theId\n end try\n if theMsg is not missing value then\n set subj to \"\"\n try\n set subj to (subject of theMsg) as string\n end try\n${outgoing ? firstRecipientSnippet('theMsg', ' ') : senderSnippet('theMsg', ' ')}\n${preview}\n set attNames to {}\n try\n set attNames to name of every attachment of theMsg\n end try\n set out to out & ${asRow(['(id of theMsg as string)', 'subj', 'sndName', 'sndAddr', 'bodyText', 'my sanitizeList(attNames)'])}\n end if\n end repeat\n return out\nend tell`, 'standard');\n\n const receivedById = new Map(chosen.map(c => [c.id, c.receivedTime]));\n return splitRecords(raw).map(record => {\n const parts = splitFields(record);\n const id = field(parts, 0);\n const attachmentNames = splitList(field(parts, 5));\n return {\n entryId: id,\n storeId: '',\n subject: field(parts, 1).trim(),\n senderName: field(parts, 2),\n senderEmail: field(parts, 3),\n receivedTime: receivedById.get(id) || '',\n bodyPreview: field(parts, 4),\n attachmentNames,\n attachmentCount: attachmentNames.length,\n folderPath,\n };\n });\n}\n\n/**\n * One email's full plain-text body. `storeId` has no macOS meaning: `message id\n * N` resolves against the application, wherever the message sits.\n */\nexport async function readEmailBody(email: EmailLocator): Promise<RawEmail> {\n const id = macMessageId(email.entryId);\n const parts = summaryFields(await runOsaScript(`tell application \"Microsoft Outlook\"\n${messageLookupSnippet(id)}\n${messageDetailSnippet(true)}\n return ${asRow(messageDetailFields(true))}\nend tell`, 'quick'));\n return {\n entryId: field(parts, MessageDetail.id) || id,\n subject: field(parts, MessageDetail.subject).trim(),\n senderName: field(parts, MessageDetail.senderName),\n senderEmail: field(parts, MessageDetail.senderEmail),\n receivedTime: field(parts, MessageDetail.receivedTime),\n body: field(parts, MessageDetail.body),\n attachmentNames: splitList(field(parts, MessageDetail.attachmentNames)),\n };\n}\n\n/**\n * Walk every folder under the Inbox for the mail matching the request.\n *\n * The filtering happens here rather than in Outlook: there is no AppleScript\n * counterpart to COM's server-side `Items.Restrict`, so each folder is indexed in\n * bulk reads and the subject and date tests run on the index. The results match\n * Windows; the cost doesn't, and a wide window over a big tree is heavier here.\n */\nexport async function searchInboxByFilter(request: SearchRequest): Promise<InboxSearchMatch[]> {\n const acct = await resolveMacAccount(request.account);\n // AppleScript reaches a child folder by name, so a path entry narrows to its leaf.\n const asNameList = (list: readonly string[]) => `{${list.map(folderLeafName).filter(Boolean).map(asString).join(', ')}}`;\n const rootInScope = request.includeFolders.length === 0 ? 'true' : 'false';\n // Sent, Drafts, Deleted and Junk hang UNDER the Inbox on an IMAP profile, so\n // their ids are collected first and the walk never descends into them — by\n // the profile's own id where it records one, through the account otherwise.\n const skipIds = ['sent items', 'deleted items', 'drafts', 'junk mail']\n .map(term => {\n const id = acct.folderIds?.[term];\n return id !== undefined\n ? ` set end of skipIds to ${id}`\n : ` try\n set end of skipIds to (id of (${term} of targetAcct))\n end try`;\n })\n .join('\\n');\n\n // Pass 1 — index every folder under the Inbox: path, id, subject, received.\n const indexed = splitRecords(await runOsaScript(`on scanFolder(theFolder, prefix, cutoff, skipIds, skipNames, onlyNames, inScope)\n set out to \"\"\n set idList to {}\n set subjList to {}\n set timeList to {}\n -- A folder the walk only passes through is never read: the bulk reads are\n -- the expensive part.\n if inScope then\n tell application \"Microsoft Outlook\"\n set idList to id of every message of theFolder\n set subjList to subject of every message of theFolder\n try\n set timeList to time received of every message of theFolder\n on error\n set timeList to {}\n end try\n end tell\n end if\n tell application \"Microsoft Outlook\"\n set subs to mail folders of theFolder\n end tell\n set hasTimes to ((count of timeList) is (count of idList))\n repeat with i from 1 to (count of idList)\n set d to missing value\n if hasTimes then set d to item i of timeList\n -- An item with no readable receive time is kept whatever the window\n -- says; dropping it would make a folder of them look empty.\n if d is missing value or d is not less than cutoff then\n set out to out & ${asRow(['prefix', '(item i of idList as string)', '(item i of subjList)', 'my isoDate(d)'])}\n end if\n end repeat\n repeat with f in subs\n set skipThis to false\n try\n if skipIds contains (id of f) then set skipThis to true\n end try\n try\n if skipNames contains ((name of f) as string) then set skipThis to true\n end try\n if not skipThis then\n set childName to \"\"\n try\n set childName to (name of f) as string\n end try\n set childScope to (count of onlyNames) is 0\n try\n if onlyNames contains childName then set childScope to true\n end try\n set out to out & my scanFolder(f, prefix & ${AS_LIST_SEP} & childName, cutoff, skipIds, skipNames, onlyNames, childScope)\n end if\n end repeat\n return out\nend scanFolder\n\ntell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'inbox', 'rootInbox')}\n set rootName to (name of rootInbox) as string\n set skipIds to {}\n${skipIds}\n set skipNames to ${asNameList(request.excludeFolders)}\n set onlyNames to ${asNameList(request.includeFolders)}\nend tell\nset cutoff to (current date) - (${asInt(request.daysBack)} * days)\nreturn my scanFolder(rootInbox, rootName, cutoff, skipIds, skipNames, onlyNames, ${rootInScope})`, 'scan'));\n\n const subjectFiltered = !!(request.subjectLike || request.subjectPattern || request.excludeReplies);\n const likeRe = request.subjectLike ? new RegExp(subjectGlobSource(request.subjectLike), 'i') : null;\n // PowerShell's -match is case-insensitive, so the Windows test is too.\n const patternRe = request.subjectPattern ? new RegExp(request.subjectPattern.source, 'i') : null;\n const candidates = indexed\n .map(record => {\n const parts = splitFields(record);\n const segments = splitList(field(parts, 0));\n return {\n folderPath: macFolderPath(request.account, segments[0] || 'Inbox', segments.slice(1)),\n id: field(parts, 1),\n subject: field(parts, 2).trim(),\n receivedTime: field(parts, 3),\n };\n })\n .filter(candidate => {\n if (subjectFiltered && !candidate.subject) return false;\n if (likeRe && !likeRe.test(candidate.subject)) return false;\n if (patternRe && !patternRe.test(candidate.subject)) return false;\n if (request.excludeReplies && REPLY_PREFIX.test(candidate.subject)) return false;\n return true;\n });\n if (candidates.length === 0) return [];\n\n // Pass 2 — senders, attachment names and (when asked) bodies, for the survivors only.\n const body = request.includeBody\n ? ` set bodyText to \"\"\n try\n set bodyText to (plain text content of theMsg) as string\n end try`\n : ' set bodyText to \"\"';\n const details = new Map<string, {\n senderName: string;\n senderEmail: string;\n attachmentNames: string[];\n body: string\n }>();\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n set out to \"\"\n repeat with theId in ${asIdList(candidates.map(c => c.id))}\n set theMsg to missing value\n try\n set theMsg to message id theId\n end try\n if theMsg is not missing value then\n${senderSnippet('theMsg', ' ')}\n set attNames to {}\n try\n set attNames to name of every attachment of theMsg\n end try\n${body}\n set out to out & ${asRow(['(id of theMsg as string)', 'sndName', 'sndAddr', 'my sanitizeList(attNames)', 'bodyText'])}\n end if\n end repeat\n return out\nend tell`, 'scan');\n for (const record of splitRecords(raw)) {\n const parts = splitFields(record);\n details.set(field(parts, 0), {\n senderName: field(parts, 1),\n senderEmail: field(parts, 2),\n attachmentNames: splitList(field(parts, 3)),\n body: field(parts, 4),\n });\n }\n\n const matches: InboxSearchMatch[] = [];\n for (const candidate of candidates) {\n const detail = details.get(candidate.id);\n if (!detail) continue;\n // Attachment names only arrive with the details, so this test waits for them.\n if (request.requireAttachment && detail.attachmentNames.length === 0) continue;\n matches.push({\n entryId: candidate.id,\n storeId: '',\n subject: candidate.subject,\n senderName: detail.senderName,\n senderEmail: detail.senderEmail,\n receivedTime: candidate.receivedTime,\n body: detail.body,\n attachmentNames: detail.attachmentNames,\n folderPath: candidate.folderPath,\n });\n }\n return matches;\n}\n\n/**\n * The email currently selected — or open — in Outlook. `current messages`\n * covers both cases the Windows reader handles separately.\n */\nexport async function readSelectedEmail(): Promise<SelectedEmail> {\n const records = splitRecords(await runOsaScript(`tell application \"Microsoft Outlook\"\n set sel to {}\n try\n set sel to current messages\n end try\n if (count of sel) is 0 then error ${asString(`${failureTag('NOT_FOUND', 'email')}No email is selected in Outlook. Select or open an email, then try again.`)}\n set theMsg to item 1 of sel\n${messageDetailSnippet(true)}\n return ${asRow(messageDetailFields(true))}\nend tell`, 'quick'));\n if (records.length === 0) throw new NotFoundError('email', 'Outlook reported no selected email.');\n const parts = splitFields(records[0]);\n return {\n entryId: field(parts, MessageDetail.id),\n storeId: '',\n subject: field(parts, MessageDetail.subject).trim(),\n senderName: field(parts, MessageDetail.senderName),\n senderEmail: field(parts, MessageDetail.senderEmail),\n receivedTime: field(parts, MessageDetail.receivedTime),\n body: field(parts, MessageDetail.body),\n attachmentNames: splitList(field(parts, MessageDetail.attachmentNames)),\n };\n}\n\n/** Open an email in Outlook and bring Outlook forward. */\nexport async function openOutlookEmail(email: EmailLocator): Promise<void> {\n const id = macMessageId(email.entryId);\n await runOsaScript(`\ntell application \"Microsoft Outlook\"\n${messageLookupSnippet(id)}\n open theMsg\n activate\nend tell`, 'quick');\n}\n"]}