@dawnlit/outlook-bridge 1.1.1 → 2.1.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/README.md +152 -183
- package/dist/backend.d.ts +151 -0
- package/dist/backend.js +3 -0
- package/dist/backend.js.map +1 -0
- package/dist/bridge.d.ts +56 -0
- package/dist/bridge.js +507 -0
- package/dist/bridge.js.map +1 -0
- package/dist/errors.d.ts +79 -43
- package/dist/errors.js +93 -52
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +25 -52
- package/dist/index.js.map +1 -1
- package/dist/mac/accounts.d.ts +7 -2
- package/dist/mac/accounts.js +23 -6
- package/dist/mac/accounts.js.map +1 -1
- package/dist/mac/attachments.d.ts +5 -25
- package/dist/mac/attachments.js +40 -99
- package/dist/mac/attachments.js.map +1 -1
- package/dist/mac/bounces.d.ts +12 -27
- package/dist/mac/bounces.js +96 -117
- package/dist/mac/bounces.js.map +1 -1
- package/dist/mac/cleanup.d.ts +11 -25
- package/dist/mac/cleanup.js +44 -107
- package/dist/mac/cleanup.js.map +1 -1
- package/dist/mac/drafts.d.ts +15 -34
- package/dist/mac/drafts.js +113 -186
- package/dist/mac/drafts.js.map +1 -1
- package/dist/mac/folders.d.ts +12 -21
- package/dist/mac/folders.js +44 -59
- package/dist/mac/folders.js.map +1 -1
- package/dist/mac/index.d.ts +2 -22
- package/dist/mac/index.js +19 -81
- package/dist/mac/index.js.map +1 -1
- package/dist/mac/profile.d.ts +13 -0
- package/dist/mac/profile.js +149 -0
- package/dist/mac/profile.js.map +1 -0
- package/dist/mac/read.d.ts +21 -37
- package/dist/mac/read.js +198 -216
- package/dist/mac/read.js.map +1 -1
- package/dist/mac/run.d.ts +51 -38
- package/dist/mac/run.js +138 -103
- package/dist/mac/run.js.map +1 -1
- package/dist/mac/scripts.d.ts +90 -91
- package/dist/mac/scripts.js +167 -126
- package/dist/mac/scripts.js.map +1 -1
- package/dist/mac/send.d.ts +10 -20
- package/dist/mac/send.js +99 -89
- package/dist/mac/send.js.map +1 -1
- package/dist/mac/signatures.d.ts +2 -2
- package/dist/mac/signatures.js +9 -11
- package/dist/mac/signatures.js.map +1 -1
- package/dist/mac/templates.d.ts +14 -26
- package/dist/mac/templates.js +79 -120
- package/dist/mac/templates.js.map +1 -1
- package/dist/mail.d.ts +80 -46
- package/dist/mail.js +179 -73
- package/dist/mail.js.map +1 -1
- package/dist/runtime.d.ts +76 -43
- package/dist/runtime.js +103 -48
- package/dist/runtime.js.map +1 -1
- package/dist/shared/args.d.ts +48 -0
- package/dist/shared/args.js +216 -0
- package/dist/shared/args.js.map +1 -0
- package/dist/shared/attachmentMatch.d.ts +26 -20
- package/dist/shared/attachmentMatch.js +60 -23
- package/dist/shared/attachmentMatch.js.map +1 -1
- package/dist/shared/bounceReport.d.ts +11 -0
- package/dist/shared/bounceReport.js +45 -0
- package/dist/shared/bounceReport.js.map +1 -0
- package/dist/shared/bounceRules.d.ts +38 -10
- package/dist/shared/bounceRules.js +50 -32
- package/dist/shared/bounceRules.js.map +1 -1
- package/dist/shared/exec.d.ts +21 -0
- package/dist/shared/exec.js +47 -0
- package/dist/shared/exec.js.map +1 -0
- package/dist/shared/json.d.ts +17 -6
- package/dist/shared/json.js +35 -24
- package/dist/shared/json.js.map +1 -1
- package/dist/shared/locate.d.ts +31 -0
- package/dist/shared/locate.js +128 -0
- package/dist/shared/locate.js.map +1 -0
- package/dist/shared/replyBody.d.ts +31 -36
- package/dist/shared/replyBody.js +83 -72
- package/dist/shared/replyBody.js.map +1 -1
- package/dist/shared/templateLimits.d.ts +14 -0
- package/dist/shared/templateLimits.js +21 -0
- package/dist/shared/templateLimits.js.map +1 -0
- package/dist/templateBody.d.ts +69 -0
- package/dist/{outlookTemplateSections.js → templateBody.js} +80 -73
- package/dist/templateBody.js.map +1 -0
- package/dist/types.d.ts +381 -168
- package/dist/types.js +8 -9
- package/dist/types.js.map +1 -1
- package/dist/windows/accounts.d.ts +7 -12
- package/dist/windows/accounts.js +19 -34
- package/dist/windows/accounts.js.map +1 -1
- package/dist/windows/attachments.d.ts +9 -24
- package/dist/windows/attachments.js +94 -119
- package/dist/windows/attachments.js.map +1 -1
- package/dist/windows/bounces.d.ts +13 -26
- package/dist/windows/bounces.js +168 -200
- package/dist/windows/bounces.js.map +1 -1
- package/dist/windows/cleanup.d.ts +23 -23
- package/dist/windows/cleanup.js +99 -113
- package/dist/windows/cleanup.js.map +1 -1
- package/dist/windows/drafts.d.ts +16 -35
- package/dist/windows/drafts.js +156 -253
- package/dist/windows/drafts.js.map +1 -1
- package/dist/windows/folders.d.ts +8 -13
- package/dist/windows/folders.js +44 -52
- package/dist/windows/folders.js.map +1 -1
- package/dist/windows/index.d.ts +2 -27
- package/dist/windows/index.js +11 -66
- package/dist/windows/index.js.map +1 -1
- package/dist/windows/read.d.ts +24 -60
- package/dist/windows/read.js +265 -306
- package/dist/windows/read.js.map +1 -1
- package/dist/windows/run.d.ts +38 -40
- package/dist/windows/run.js +151 -112
- package/dist/windows/run.js.map +1 -1
- package/dist/windows/scripts.d.ts +65 -55
- package/dist/windows/scripts.js +109 -85
- package/dist/windows/scripts.js.map +1 -1
- package/dist/windows/send.d.ts +9 -9
- package/dist/windows/send.js +76 -88
- package/dist/windows/send.js.map +1 -1
- package/dist/windows/signatures.d.ts +4 -10
- package/dist/windows/signatures.js +30 -37
- package/dist/windows/signatures.js.map +1 -1
- package/dist/windows/templates.d.ts +12 -18
- package/dist/windows/templates.js +117 -150
- package/dist/windows/templates.js.map +1 -1
- package/package.json +5 -4
- package/dist/OutlookService.d.ts +0 -43
- package/dist/OutlookService.js +0 -137
- package/dist/OutlookService.js.map +0 -1
- package/dist/outlookTemplateSections.d.ts +0 -62
- package/dist/outlookTemplateSections.js.map +0 -1
- package/dist/shared/capabilities.d.ts +0 -3
- package/dist/shared/capabilities.js +0 -9
- package/dist/shared/capabilities.js.map +0 -1
package/dist/mac/templates.js
CHANGED
|
@@ -4,52 +4,37 @@ exports.readTemplateEmails = readTemplateEmails;
|
|
|
4
4
|
exports.saveTemplateEmail = saveTemplateEmail;
|
|
5
5
|
exports.editEmailTemplate = editEmailTemplate;
|
|
6
6
|
// Template emails: ordinary mail items kept in a mailbox folder and reused as
|
|
7
|
-
//
|
|
7
|
+
// email bodies, plus the compose-window editor for one.
|
|
8
8
|
//
|
|
9
|
-
// Outlook for Mac serves a message's HTML through `content`
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// Outlook for Mac serves a message's HTML through `content` — the same thing
|
|
10
|
+
// COM's HTMLBody returns — which is what makes templates portable between the
|
|
11
|
+
// two platforms.
|
|
12
12
|
const run_1 = require("./run");
|
|
13
13
|
const scripts_1 = require("./scripts");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
const templateLimits_1 = require("../shared/templateLimits");
|
|
15
|
+
const templateBody_1 = require("../templateBody");
|
|
16
16
|
const errors_1 = require("../errors");
|
|
17
|
-
/**
|
|
18
|
-
const TEMPLATE_SEARCH_DEPTH = 3;
|
|
19
|
-
/** The cap Windows applies to a template body; a Word-generated one is huge. */
|
|
20
|
-
const MAX_TEMPLATE_HTML = 100000;
|
|
21
|
-
/** How much plain text stands in for a body when one wasn't asked for. */
|
|
22
|
-
const PREVIEW_CHARS = 200;
|
|
23
|
-
/**
|
|
24
|
-
* Embedded (cid:) images live as attachments on the TEMPLATE item, so reusing
|
|
25
|
-
* the HTML on a new email shows a broken "linked image" placeholder, and
|
|
26
|
-
* rewriting the refs renders invisibly. Neither works, so the img tags go —
|
|
27
|
-
* template emails are text/HTML only.
|
|
28
|
-
*/
|
|
17
|
+
/** A template body without its embedded images — see EMBEDDED_IMAGE_SOURCE. */
|
|
29
18
|
function stripEmbeddedImages(html) {
|
|
30
|
-
return html.replace(
|
|
19
|
+
return html.replace(new RegExp(templateLimits_1.EMBEDDED_IMAGE_SOURCE, 'gi'), '');
|
|
31
20
|
}
|
|
32
21
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* folderFound:false plus the mailbox's folder names instead of throwing, so the
|
|
36
|
-
* caller can ask the user whether to create it rather than fail.
|
|
22
|
+
* The template emails in a mailbox folder, newest first; a missing folder is
|
|
23
|
+
* reported as folderFound:false with the mailbox's top-level folder names.
|
|
37
24
|
*
|
|
38
|
-
* Bodies are read in a second pass, for the chosen templates only
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* the buffer — the same reason the Windows reader filters before reading.
|
|
25
|
+
* Bodies are read in a second pass, for the chosen templates only: a folder of
|
|
26
|
+
* Word-sized templates is megabytes, and pulling all of them through stdout on
|
|
27
|
+
* a call that wanted one is what overruns the output limit.
|
|
42
28
|
*/
|
|
43
|
-
async function readTemplateEmails(
|
|
44
|
-
const
|
|
45
|
-
const wanted = (subject || '').trim().toLowerCase();
|
|
29
|
+
async function readTemplateEmails(request) {
|
|
30
|
+
const acct = await (0, scripts_1.resolveMacAccount)(request.account);
|
|
46
31
|
// Pass 1 — find the folder and index it: three bulk reads, no bodies.
|
|
47
|
-
const
|
|
32
|
+
const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(`${scripts_1.FIND_FOLDER_HANDLER}
|
|
48
33
|
tell application "Microsoft Outlook"
|
|
49
|
-
${(0, scripts_1.accountLookupSnippet)(
|
|
50
|
-
|
|
34
|
+
${(0, scripts_1.accountLookupSnippet)(acct)}
|
|
35
|
+
${(0, scripts_1.rootFolderSnippet)(acct, 'root folder', 'rootFolder')}
|
|
51
36
|
end tell
|
|
52
|
-
set theFolder to my findFolderByName(rootFolder,
|
|
37
|
+
set theFolder to my findFolderByName(rootFolder, ${(0, run_1.asString)(request.folder)}, ${(0, run_1.asInt)(templateLimits_1.TEMPLATE_SEARCH_DEPTH)})
|
|
53
38
|
tell application "Microsoft Outlook"
|
|
54
39
|
if theFolder is missing value then
|
|
55
40
|
set names to {}
|
|
@@ -68,52 +53,43 @@ tell application "Microsoft Outlook"
|
|
|
68
53
|
set modList to {}
|
|
69
54
|
end try
|
|
70
55
|
set hasMods to ((count of modList) is (count of idList))
|
|
71
|
-
|
|
56
|
+
-- The folder may sit up to the search depth down, so its whole chain is
|
|
57
|
+
-- reported, not just its name: the path is the one Windows' FolderPath gives.
|
|
58
|
+
${(0, scripts_1.folderChainSnippet)(' ')}
|
|
59
|
+
set out to ${(0, run_1.asRow)(['"1"', 'my sanitizeList(chainNames)'])}
|
|
72
60
|
repeat with i from 1 to (count of idList)
|
|
73
61
|
set modAt to ""
|
|
74
62
|
if hasMods then set modAt to my isoDate(item i of modList)
|
|
75
|
-
set out to out & ${(0, run_1.asRow)([
|
|
76
|
-
'(item i of idList as string)',
|
|
77
|
-
'(item i of subjList)',
|
|
78
|
-
'modAt',
|
|
79
|
-
])}
|
|
63
|
+
set out to out & ${(0, run_1.asRow)(['(item i of idList as string)', '(item i of subjList)', 'modAt'])}
|
|
80
64
|
end repeat
|
|
81
65
|
return out
|
|
82
|
-
end tell
|
|
83
|
-
const
|
|
84
|
-
const header = (0, run_1.splitFields)(records[0] || '');
|
|
66
|
+
end tell`, 'standard'));
|
|
67
|
+
const header = (0, run_1.splitFields)(records[0] ?? '');
|
|
85
68
|
if ((0, run_1.field)(header, 0) !== '1') {
|
|
86
|
-
return {
|
|
87
|
-
folderFound: false,
|
|
88
|
-
folderPath: '',
|
|
89
|
-
templates: [],
|
|
90
|
-
availableFolders: (0, run_1.splitList)((0, run_1.field)(header, 1)),
|
|
91
|
-
};
|
|
69
|
+
return { folderFound: false, folderPath: '', templates: [], availableFolders: (0, run_1.splitList)((0, run_1.field)(header, 1)) };
|
|
92
70
|
}
|
|
93
|
-
const
|
|
94
|
-
const
|
|
71
|
+
const chain = (0, run_1.splitList)((0, run_1.field)(header, 1)).reverse();
|
|
72
|
+
const folderPath = chain.length
|
|
73
|
+
? (0, scripts_1.macFolderPath)(request.account, chain[0], chain.slice(1))
|
|
74
|
+
: (0, scripts_1.macFolderPath)(request.account, request.folder, []);
|
|
75
|
+
const wanted = (request.subject ?? '').toLowerCase();
|
|
76
|
+
const chosen = records.slice(1)
|
|
77
|
+
.map(record => {
|
|
95
78
|
const parts = (0, run_1.splitFields)(record);
|
|
96
|
-
return {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
});
|
|
102
|
-
// Newest first, matching the Windows reader's Sort on LastModificationTime —
|
|
103
|
-
// and done before the cap, so "the newest 20" means that rather than an
|
|
104
|
-
// arbitrary 20. 'yyyy-MM-dd HH:mm' sorts lexicographically.
|
|
105
|
-
indexed.sort((a, b) => b.lastModified.localeCompare(a.lastModified));
|
|
106
|
-
const chosen = indexed
|
|
79
|
+
return { id: (0, run_1.field)(parts, 0), subject: (0, run_1.field)(parts, 1).trim(), lastModified: (0, run_1.field)(parts, 2) };
|
|
80
|
+
})
|
|
81
|
+
// Newest first, before the cap, so "the newest 20" means that.
|
|
82
|
+
.sort((a, b) => b.lastModified.localeCompare(a.lastModified))
|
|
107
83
|
.filter(item => !wanted || item.subject.toLowerCase() === wanted)
|
|
108
|
-
.slice(0,
|
|
109
|
-
if (chosen.length === 0)
|
|
84
|
+
.slice(0, request.limit);
|
|
85
|
+
if (chosen.length === 0)
|
|
110
86
|
return { folderFound: true, folderPath, templates: [], availableFolders: [] };
|
|
111
|
-
}
|
|
112
87
|
// Pass 2 — the bodies, for the chosen templates only.
|
|
113
|
-
const bodyProperty = includeBody ? 'content' : 'plain text content';
|
|
114
|
-
const
|
|
88
|
+
const bodyProperty = request.includeBody ? 'content' : 'plain text content';
|
|
89
|
+
const bodies = new Map();
|
|
90
|
+
const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
|
|
115
91
|
set out to ""
|
|
116
|
-
repeat with theId in
|
|
92
|
+
repeat with theId in ${(0, run_1.asIdList)(chosen.map(item => item.id))}
|
|
117
93
|
set theMsg to missing value
|
|
118
94
|
try
|
|
119
95
|
set theMsg to message id theId
|
|
@@ -127,26 +103,23 @@ end tell`;
|
|
|
127
103
|
end if
|
|
128
104
|
end repeat
|
|
129
105
|
return out
|
|
130
|
-
end tell
|
|
131
|
-
const
|
|
132
|
-
for (const record of (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(bodyScript, 120000))) {
|
|
106
|
+
end tell`, 'standard');
|
|
107
|
+
for (const record of (0, run_1.splitRecords)(raw)) {
|
|
133
108
|
const parts = (0, run_1.splitFields)(record);
|
|
134
109
|
bodies.set((0, run_1.field)(parts, 0), (0, run_1.field)(parts, 1));
|
|
135
110
|
}
|
|
136
111
|
const templates = chosen.map(item => {
|
|
137
|
-
const body = bodies.get(item.id)
|
|
138
|
-
const html = includeBody
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
// marker cannot have been split.
|
|
144
|
-
const markers = (0, outlookTemplateSections_1.findTemplateMarkers)(includeBody ? html : body);
|
|
112
|
+
const body = bodies.get(item.id) ?? '';
|
|
113
|
+
const html = request.includeBody ? stripEmbeddedImages(body).slice(0, templateLimits_1.MAX_TEMPLATE_HTML) : '';
|
|
114
|
+
// With the HTML in hand it is authoritative (markers survive Word
|
|
115
|
+
// splitting them across tags); without it, the plain text is scanned,
|
|
116
|
+
// where a marker can't have been split.
|
|
117
|
+
const markers = (0, templateBody_1.findTemplateMarkers)(request.includeBody ? html : body);
|
|
145
118
|
return {
|
|
146
119
|
entryId: item.id,
|
|
147
120
|
subject: item.subject,
|
|
148
121
|
htmlBody: html,
|
|
149
|
-
bodyPreview: includeBody ? '' : body.trim().slice(0,
|
|
122
|
+
bodyPreview: request.includeBody ? '' : body.trim().slice(0, templateLimits_1.TEMPLATE_PREVIEW_CHARS),
|
|
150
123
|
sections: markers.sections,
|
|
151
124
|
placeholders: markers.placeholders,
|
|
152
125
|
lastModified: item.lastModified,
|
|
@@ -155,27 +128,25 @@ end tell`;
|
|
|
155
128
|
return { folderFound: true, folderPath, templates, availableFolders: [] };
|
|
156
129
|
}
|
|
157
130
|
/**
|
|
158
|
-
* Save a new template email into a
|
|
159
|
-
*
|
|
160
|
-
* plain unsent mail (subject + HTML body) that can be edited in Outlook.
|
|
161
|
-
* Never overwrites an existing item — it always adds a new one, so check with
|
|
162
|
-
* readTemplateEmails first and only call after the user has agreed to create it.
|
|
131
|
+
* Save a new template email into a folder, creating the folder at the mailbox
|
|
132
|
+
* root when absent. Always adds a new item — never overwrites one.
|
|
163
133
|
*/
|
|
164
|
-
async function saveTemplateEmail(
|
|
165
|
-
const
|
|
134
|
+
async function saveTemplateEmail(request) {
|
|
135
|
+
const acct = await (0, scripts_1.resolveMacAccount)(request.account);
|
|
136
|
+
const parts = (0, run_1.summaryFields)(await (0, run_1.runOsaScript)(`${scripts_1.FIND_FOLDER_HANDLER}
|
|
166
137
|
tell application "Microsoft Outlook"
|
|
167
|
-
${(0, scripts_1.accountLookupSnippet)(
|
|
168
|
-
|
|
138
|
+
${(0, scripts_1.accountLookupSnippet)(acct)}
|
|
139
|
+
${(0, scripts_1.rootFolderSnippet)(acct, 'root folder', 'rootFolder')}
|
|
169
140
|
end tell
|
|
170
|
-
set theFolder to my findFolderByName(rootFolder,
|
|
141
|
+
set theFolder to my findFolderByName(rootFolder, ${(0, run_1.asString)(request.folder)}, ${(0, run_1.asInt)(templateLimits_1.TEMPLATE_SEARCH_DEPTH)})
|
|
171
142
|
tell application "Microsoft Outlook"
|
|
172
143
|
set wasCreated to false
|
|
173
144
|
if theFolder is missing value then
|
|
174
|
-
set theFolder to (make new mail folder at rootFolder with properties {name
|
|
145
|
+
set theFolder to (make new mail folder at rootFolder with properties {name:${(0, run_1.asString)(request.folder)}})
|
|
175
146
|
set wasCreated to true
|
|
176
147
|
end if
|
|
177
148
|
set countBefore to count of messages of theFolder
|
|
178
|
-
set newMsg to make new outgoing message with properties {subject
|
|
149
|
+
set newMsg to make new outgoing message with properties {subject:${(0, run_1.asString)(request.subject)}, content:${(0, run_1.asString)(request.htmlBody)}}
|
|
179
150
|
try
|
|
180
151
|
set account of newMsg to targetAcct
|
|
181
152
|
end try
|
|
@@ -184,37 +155,28 @@ tell application "Microsoft Outlook"
|
|
|
184
155
|
move newMsg to theFolder
|
|
185
156
|
if (count of messages of theFolder) is not greater than countBefore then error "Outlook did not file the template in '" & (name of theFolder) & "'."
|
|
186
157
|
return ${(0, run_1.asRow)(['(name of theFolder as string)', '(wasCreated as string)'])}
|
|
187
|
-
end tell
|
|
188
|
-
const parts = (0, run_1.summaryFields)(await (0, run_1.runOsaScript)(script, 120000));
|
|
158
|
+
end tell`, 'standard'));
|
|
189
159
|
return {
|
|
190
|
-
folderPath: (0, scripts_1.macFolderPath)(
|
|
160
|
+
folderPath: (0, scripts_1.macFolderPath)(request.account, (0, run_1.field)(parts, 0) || request.folder, []),
|
|
191
161
|
folderCreated: (0, run_1.boolField)(parts, 1),
|
|
192
162
|
};
|
|
193
163
|
}
|
|
194
164
|
/**
|
|
195
|
-
* Open
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* Deliberately unbounded: the run lasts as long as the person is editing. Give
|
|
199
|
-
* it an AbortSignal (`bridge.withOptions({ signal })`) if the caller needs a way
|
|
200
|
-
* to give up on them.
|
|
201
|
-
*
|
|
202
|
-
* The macOS half of the round trip differs from Windows in one visible way: an
|
|
203
|
-
* edited draft is filed by answering Outlook's own "save this message?" prompt
|
|
204
|
-
* on close, so the subject tells the user to save rather than to press a key.
|
|
165
|
+
* Open a compose window pre-filled with the HTML, wait for it to close, and
|
|
166
|
+
* return the saved draft's HTML. On macOS the edit is kept by answering
|
|
167
|
+
* Outlook's own "save this message?" prompt on close.
|
|
205
168
|
*/
|
|
206
|
-
async function editEmailTemplate(
|
|
207
|
-
const subject = `${label} - Save and close when done`;
|
|
208
|
-
const
|
|
209
|
-
set editSubject to
|
|
210
|
-
set draftMsg to make new outgoing message with properties {subject:editSubject, content
|
|
169
|
+
async function editEmailTemplate(request) {
|
|
170
|
+
const subject = `${request.label} - Save and close when done`;
|
|
171
|
+
const saved = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
|
|
172
|
+
set editSubject to ${(0, run_1.asString)(subject)}
|
|
173
|
+
set draftMsg to make new outgoing message with properties {subject:editSubject, content:${(0, run_1.asString)(request.html)}}
|
|
211
174
|
open draftMsg
|
|
212
175
|
activate
|
|
213
176
|
end tell
|
|
214
177
|
|
|
215
|
-
-- Poll until the compose window is gone
|
|
216
|
-
--
|
|
217
|
-
-- than by counting windows the user may also have open.
|
|
178
|
+
-- Poll until the compose window is gone, identifying ours by subject rather
|
|
179
|
+
-- than counting windows the person may also have open.
|
|
218
180
|
set stillOpen to true
|
|
219
181
|
repeat while stillOpen
|
|
220
182
|
delay 0.7
|
|
@@ -234,9 +196,8 @@ repeat while stillOpen
|
|
|
234
196
|
end repeat
|
|
235
197
|
|
|
236
198
|
tell application "Microsoft Outlook"
|
|
237
|
-
-- Prefer the saved draft: it
|
|
238
|
-
--
|
|
239
|
-
-- they don't pile up in the Drafts folder.
|
|
199
|
+
-- Prefer the saved draft: it is what the person chose to keep, and it
|
|
200
|
+
-- outlives the window. Every editor draft is removed so none pile up.
|
|
240
201
|
set savedHtml to ""
|
|
241
202
|
try
|
|
242
203
|
repeat with acctList in {exchange accounts, imap accounts, pop accounts}
|
|
@@ -255,11 +216,9 @@ tell application "Microsoft Outlook"
|
|
|
255
216
|
end repeat
|
|
256
217
|
end try
|
|
257
218
|
return my sanitize(savedHtml)
|
|
258
|
-
end tell
|
|
259
|
-
// 0 disables the timeout: this run is as long as the edit takes.
|
|
260
|
-
const saved = await (0, run_1.runOsaScript)(script, 0);
|
|
219
|
+
end tell`, 'interactive');
|
|
261
220
|
if (!saved) {
|
|
262
|
-
throw new errors_1.NotFoundError('template', 'No template saved.
|
|
221
|
+
throw new errors_1.NotFoundError('template', 'No template was saved. Save the draft before closing the window.');
|
|
263
222
|
}
|
|
264
223
|
return saved;
|
|
265
224
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/mac/templates.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/mac/templates.ts"],"names":[],"mappings":"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","sourcesContent":["// Template emails: ordinary mail items kept in a mailbox folder and reused as\n// email bodies, plus the compose-window editor for one.\n//\n// Outlook for Mac serves a message's HTML through `content` — the same thing\n// COM's HTMLBody returns — which is what makes templates portable between the\n// two platforms.\nimport {\n asIdList,\n asInt,\n asRow,\n asString,\n boolField,\n field,\n runOsaScript,\n splitFields,\n splitList,\n splitRecords,\n summaryFields,\n} from './run';\nimport {\n accountLookupSnippet,\n FIND_FOLDER_HANDLER,\n folderChainSnippet,\n macFolderPath,\n resolveMacAccount,\n rootFolderSnippet,\n} from './scripts';\nimport {\n EMBEDDED_IMAGE_SOURCE,\n MAX_TEMPLATE_HTML,\n TEMPLATE_PREVIEW_CHARS,\n TEMPLATE_SEARCH_DEPTH,\n} from '../shared/templateLimits';\nimport { findTemplateMarkers } from '../templateBody';\nimport { NotFoundError } from '../errors';\nimport type { EditTemplateRequest, ReadTemplatesRequest, SaveTemplateRequest } from '../backend';\nimport type { SaveTemplateResult, TemplateEmail, TemplateFolderResult } from '../types';\n\n/** A template body without its embedded images — see EMBEDDED_IMAGE_SOURCE. */\nfunction stripEmbeddedImages(html: string): string {\n return html.replace(new RegExp(EMBEDDED_IMAGE_SOURCE, 'gi'), '');\n}\n\n/**\n * The template emails in a mailbox folder, newest first; a missing folder is\n * reported as folderFound:false with the mailbox's top-level folder names.\n *\n * Bodies are read in a second pass, for the chosen templates only: a folder of\n * Word-sized templates is megabytes, and pulling all of them through stdout on\n * a call that wanted one is what overruns the output limit.\n */\nexport async function readTemplateEmails(request: ReadTemplatesRequest): Promise<TemplateFolderResult> {\n const acct = await resolveMacAccount(request.account);\n // Pass 1 — find the folder and index it: three bulk reads, no bodies.\n const records = splitRecords(await runOsaScript(`${FIND_FOLDER_HANDLER}\ntell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'root folder', 'rootFolder')}\nend tell\nset theFolder to my findFolderByName(rootFolder, ${asString(request.folder)}, ${asInt(TEMPLATE_SEARCH_DEPTH)})\ntell application \"Microsoft Outlook\"\n if theFolder is missing value then\n set names to {}\n repeat with f in (mail folders of rootFolder)\n try\n set end of names to (name of f) as string\n end try\n end repeat\n return ${asRow(['\"0\"', 'my sanitizeList(names)'])}\n end if\n set idList to id of every message of theFolder\n set subjList to subject of every message of theFolder\n try\n set modList to modification date of every message of theFolder\n on error\n set modList to {}\n end try\n set hasMods to ((count of modList) is (count of idList))\n -- The folder may sit up to the search depth down, so its whole chain is\n -- reported, not just its name: the path is the one Windows' FolderPath gives.\n${folderChainSnippet(' ')}\n set out to ${asRow(['\"1\"', 'my sanitizeList(chainNames)'])}\n repeat with i from 1 to (count of idList)\n set modAt to \"\"\n if hasMods then set modAt to my isoDate(item i of modList)\n set out to out & ${asRow(['(item i of idList as string)', '(item i of subjList)', 'modAt'])}\n end repeat\n return out\nend tell`, 'standard'));\n\n const header = splitFields(records[0] ?? '');\n if (field(header, 0) !== '1') {\n return { folderFound: false, folderPath: '', templates: [], availableFolders: splitList(field(header, 1)) };\n }\n const chain = splitList(field(header, 1)).reverse();\n const folderPath = chain.length\n ? macFolderPath(request.account, chain[0], chain.slice(1))\n : macFolderPath(request.account, request.folder, []);\n const wanted = (request.subject ?? '').toLowerCase();\n const chosen = records.slice(1)\n .map(record => {\n const parts = splitFields(record);\n return { id: field(parts, 0), subject: field(parts, 1).trim(), lastModified: field(parts, 2) };\n })\n // Newest first, before the cap, so \"the newest 20\" means that.\n .sort((a, b) => b.lastModified.localeCompare(a.lastModified))\n .filter(item => !wanted || item.subject.toLowerCase() === wanted)\n .slice(0, request.limit);\n if (chosen.length === 0) return { folderFound: true, folderPath, templates: [], availableFolders: [] };\n\n // Pass 2 — the bodies, for the chosen templates only.\n const bodyProperty = request.includeBody ? 'content' : 'plain text content';\n const bodies = new Map<string, string>();\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n set out to \"\"\n repeat with theId in ${asIdList(chosen.map(item => item.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 bodyText to \"\"\n try\n set bodyText to (${bodyProperty} of theMsg) as string\n end try\n set out to out & ${asRow(['(theId as string)', 'bodyText'])}\n end if\n end repeat\n return out\nend tell`, 'standard');\n for (const record of splitRecords(raw)) {\n const parts = splitFields(record);\n bodies.set(field(parts, 0), field(parts, 1));\n }\n\n const templates: TemplateEmail[] = chosen.map(item => {\n const body = bodies.get(item.id) ?? '';\n const html = request.includeBody ? stripEmbeddedImages(body).slice(0, MAX_TEMPLATE_HTML) : '';\n // With the HTML in hand it is authoritative (markers survive Word\n // splitting them across tags); without it, the plain text is scanned,\n // where a marker can't have been split.\n const markers = findTemplateMarkers(request.includeBody ? html : body);\n return {\n entryId: item.id,\n subject: item.subject,\n htmlBody: html,\n bodyPreview: request.includeBody ? '' : body.trim().slice(0, TEMPLATE_PREVIEW_CHARS),\n sections: markers.sections,\n placeholders: markers.placeholders,\n lastModified: item.lastModified,\n };\n });\n return { folderFound: true, folderPath, templates, availableFolders: [] };\n}\n\n/**\n * Save a new template email into a folder, creating the folder at the mailbox\n * root when absent. Always adds a new item — never overwrites one.\n */\nexport async function saveTemplateEmail(request: SaveTemplateRequest): Promise<SaveTemplateResult> {\n const acct = await resolveMacAccount(request.account);\n const parts = summaryFields(await runOsaScript(`${FIND_FOLDER_HANDLER}\ntell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'root folder', 'rootFolder')}\nend tell\nset theFolder to my findFolderByName(rootFolder, ${asString(request.folder)}, ${asInt(TEMPLATE_SEARCH_DEPTH)})\ntell application \"Microsoft Outlook\"\n set wasCreated to false\n if theFolder is missing value then\n set theFolder to (make new mail folder at rootFolder with properties {name:${asString(request.folder)}})\n set wasCreated to true\n end if\n set countBefore to count of messages of theFolder\n set newMsg to make new outgoing message with properties {subject:${asString(request.subject)}, content:${asString(request.htmlBody)}}\n try\n set account of newMsg to targetAcct\n end try\n -- 'move' reports success even where it silently does nothing, so a template\n -- that was never filed must not be reported as saved.\n move newMsg to theFolder\n if (count of messages of theFolder) is not greater than countBefore then error \"Outlook did not file the template in '\" & (name of theFolder) & \"'.\"\n return ${asRow(['(name of theFolder as string)', '(wasCreated as string)'])}\nend tell`, 'standard'));\n return {\n folderPath: macFolderPath(request.account, field(parts, 0) || request.folder, []),\n folderCreated: boolField(parts, 1),\n };\n}\n\n/**\n * Open a compose window pre-filled with the HTML, wait for it to close, and\n * return the saved draft's HTML. On macOS the edit is kept by answering\n * Outlook's own \"save this message?\" prompt on close.\n */\nexport async function editEmailTemplate(request: EditTemplateRequest): Promise<string> {\n const subject = `${request.label} - Save and close when done`;\n const saved = await runOsaScript(`tell application \"Microsoft Outlook\"\n set editSubject to ${asString(subject)}\n set draftMsg to make new outgoing message with properties {subject:editSubject, content:${asString(request.html)}}\n open draftMsg\n activate\nend tell\n\n-- Poll until the compose window is gone, identifying ours by subject rather\n-- than counting windows the person may also have open.\nset stillOpen to true\nrepeat while stillOpen\n delay 0.7\n set stillOpen to false\n tell application \"Microsoft Outlook\"\n try\n repeat with w in draft windows\n try\n if ((subject of (object of w)) as string) is editSubject then\n set stillOpen to true\n exit repeat\n end if\n end try\n end repeat\n end try\n end tell\nend repeat\n\ntell application \"Microsoft Outlook\"\n -- Prefer the saved draft: it is what the person chose to keep, and it\n -- outlives the window. Every editor draft is removed so none pile up.\n set savedHtml to \"\"\n try\n repeat with acctList in {exchange accounts, imap accounts, pop accounts}\n repeat with a in acctList\n try\n repeat with m in (messages of (drafts of a))\n try\n if ((subject of m) as string) is editSubject then\n if savedHtml is \"\" then set savedHtml to (content of m) as string\n delete m\n end if\n end try\n end repeat\n end try\n end repeat\n end repeat\n end try\n return my sanitize(savedHtml)\nend tell`, 'interactive');\n if (!saved) {\n throw new NotFoundError('template', 'No template was saved. Save the draft before closing the window.');\n }\n return saved;\n}\n"]}
|
package/dist/mail.d.ts
CHANGED
|
@@ -1,69 +1,103 @@
|
|
|
1
|
-
import type { MailFolderRef } from './types';
|
|
1
|
+
import type { DeleteMailOutcome, DeleteMailResult, MailFolderRef } from './types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* rows come back, how deep a folder walk goes — so they are stated here rather
|
|
7
|
-
* than once per platform, which is how the two came to disagree about what a
|
|
8
|
-
* `daysBack` of 0 means.
|
|
3
|
+
* Outlook's olDefaultFolders ids for the folders this package addresses by
|
|
4
|
+
* role rather than by name. The ids are Outlook's own, and a folder's NAME is
|
|
5
|
+
* localized, so a role is always resolved through its id.
|
|
9
6
|
*/
|
|
10
|
-
export declare
|
|
7
|
+
export declare const FolderId: Readonly<{
|
|
8
|
+
DeletedItems: 3;
|
|
9
|
+
Outbox: 4;
|
|
10
|
+
SentMail: 5;
|
|
11
|
+
Inbox: 6;
|
|
12
|
+
Drafts: 16;
|
|
13
|
+
Junk: 23;
|
|
14
|
+
}>;
|
|
11
15
|
/**
|
|
12
|
-
* The
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* substitutes for it.
|
|
16
|
-
*
|
|
17
|
-
* A well-known name always wins over a user folder of the same name — reach the
|
|
18
|
-
* latter by qualifying it (`Inbox\Drafts`).
|
|
16
|
+
* The folders addressable by name rather than by walking from the Inbox, with
|
|
17
|
+
* their olDefaultFolders id. A well-known name wins over a user folder of the
|
|
18
|
+
* same name; reach the latter by qualifying it (`Inbox\Drafts`).
|
|
19
19
|
*/
|
|
20
|
-
export declare const WELL_KNOWN_FOLDERS: Record<string, number
|
|
20
|
+
export declare const WELL_KNOWN_FOLDERS: Readonly<Record<string, number>>;
|
|
21
21
|
/**
|
|
22
|
-
* Why `deleteOutlookEmails` refuses
|
|
23
|
-
*
|
|
24
|
-
* It reaches the caller verbatim in a per-email `reason`, so the two generated
|
|
25
|
-
* scripts must not word it independently — the same reasoning that put the
|
|
26
|
-
* attachment "not found" sentence in `shared/attachmentMatch.ts`. It also names
|
|
27
|
-
* the option a consumer of THIS package actually passes: the text used to say
|
|
28
|
-
* `allow_protected`, which is the tool-layer spelling and not a name this
|
|
29
|
-
* package exposes.
|
|
22
|
+
* Why `deleteOutlookEmails` refuses an item, worded once for both platforms —
|
|
23
|
+
* it reaches the caller verbatim as a per-item `reason`.
|
|
30
24
|
*/
|
|
31
25
|
export declare const PROTECTED_MAIL_REASON = "received or sent mail (Inbox/Sent Items or a subfolder) - pass allowProtected to override";
|
|
26
|
+
/** The status a delete script reported for one item; anything it shouldn't have said is a failure. */
|
|
27
|
+
export declare function deleteStatus(reported: string): DeleteMailOutcome['status'];
|
|
28
|
+
/** A deleteOutlookEmails result: every outcome, and how many ended each way. */
|
|
29
|
+
export declare function deleteMailResult(dryRun: boolean, items: DeleteMailOutcome[]): DeleteMailResult;
|
|
32
30
|
/**
|
|
33
|
-
* Roots whose items are
|
|
34
|
-
*
|
|
35
|
-
* Outgoing mail carries a sent timestamp where received mail carries a received
|
|
36
|
-
* one, and both platforms have to pick the same folders out on that basis —
|
|
37
|
-
* which is why it lives beside `WELL_KNOWN_FOLDERS` rather than as raw
|
|
38
|
-
* `olDefaultFolders` ids compared inline in each reader.
|
|
31
|
+
* Roots whose items are outgoing mail, which carries a sent time where incoming
|
|
32
|
+
* mail carries a received one — so a date filter has to know which it's on.
|
|
39
33
|
*/
|
|
40
34
|
export declare function isOutgoingRoot(rootId: number): boolean;
|
|
41
35
|
/**
|
|
42
|
-
*
|
|
36
|
+
* Roots an Inbox walk must never descend into.
|
|
43
37
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
38
|
+
* On an Exchange profile these sit beside the Inbox and a walk from it can't
|
|
39
|
+
* reach them anyway. On an IMAP profile Outlook nests them UNDER the Inbox, so
|
|
40
|
+
* the same walk would hand back mail already sent, drafted or thrown away as if
|
|
41
|
+
* it had just arrived. They are matched by id, never by name: the names are
|
|
42
|
+
* localized.
|
|
43
|
+
*/
|
|
44
|
+
export declare const NON_INCOMING_ROOTS: readonly number[];
|
|
45
|
+
/** The reply/forward prefixes as one case-insensitive pattern source. */
|
|
46
|
+
export declare const REPLY_PREFIX_SOURCE: string;
|
|
47
|
+
export declare const REPLY_PREFIX: RegExp;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a subject opens on a reply or forward prefix.
|
|
50
|
+
*
|
|
51
|
+
* This reads what the subject claims, not how the email was made: a forward
|
|
52
|
+
* carries a prefix too, and a client can leave one off a real reply.
|
|
53
|
+
*/
|
|
54
|
+
export declare function hasReplyPrefix(subject: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* The subject every message in a thread shares: every reply and forward prefix
|
|
57
|
+
* stripped, however many clients stacked them (`RE: FW: RE[2]: Rate request`
|
|
58
|
+
* is `Rate request`), and whitespace collapsed. Case is kept, so lower-case
|
|
59
|
+
* both sides to compare two threads.
|
|
60
|
+
*/
|
|
61
|
+
export declare function threadSubject(subject: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* A subject glob as an anchored regex source: `*` matches any run, `?` one
|
|
64
|
+
* character, everything else itself. Written with constructs JavaScript and
|
|
65
|
+
* .NET read identically, so both platforms apply exactly the same test.
|
|
66
|
+
*/
|
|
67
|
+
export declare function subjectGlobSource(glob: string): string;
|
|
68
|
+
/** The leaf name of a folder path or bare name. */
|
|
69
|
+
export declare function folderLeafName(entry: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a folder string to a well-known root plus the segments below it.
|
|
48
72
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
73
|
+
* Accepts every shape a person has to hand: a bare name ('Invoices'), a
|
|
74
|
+
* relative path ('Invoices\Paid'), a well-known folder ('Sent Items'), a path
|
|
75
|
+
* under one ('Deleted Items\2026'), and the full path listInboxFolders prints
|
|
76
|
+
* ('\\team@example.com\Inbox\Invoices'). Anything not starting at a well-known
|
|
77
|
+
* folder is taken as relative to the Inbox.
|
|
51
78
|
*/
|
|
52
79
|
export declare function mailFolderRef(folder: string): MailFolderRef;
|
|
80
|
+
/**
|
|
81
|
+
* A caller's folder option as a reference: none given means the Inbox root,
|
|
82
|
+
* and a string that names no folder at all (only separators) is refused rather
|
|
83
|
+
* than silently read as the Inbox root.
|
|
84
|
+
*/
|
|
85
|
+
export declare function folderOption(folder: string | undefined): {
|
|
86
|
+
ref: MailFolderRef;
|
|
87
|
+
label: string;
|
|
88
|
+
};
|
|
53
89
|
/**
|
|
54
90
|
* Split a plain-text reply into the sender's own text and the quoted thread
|
|
55
91
|
* below it.
|
|
56
92
|
*
|
|
57
|
-
* This matters more than it looks: the quoted original
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* worse failure than the truncation this exists to fix.
|
|
93
|
+
* This matters more than it looks: the quoted original carries the text of the
|
|
94
|
+
* message being answered, and handing a reader one blob invites a figure from
|
|
95
|
+
* that message to be read back as the sender's own.
|
|
61
96
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* outcome worth avoiding.
|
|
97
|
+
* Splits at the earliest separator Outlook or the common webmail clients emit.
|
|
98
|
+
* If that would leave no new text at all — a bottom-posted reply, or a body
|
|
99
|
+
* that opens on a quote — the split is abandoned and everything is `body`,
|
|
100
|
+
* since losing the sender's actual words is the one outcome worth avoiding.
|
|
67
101
|
*/
|
|
68
102
|
export declare function splitQuotedOriginal(text: string): {
|
|
69
103
|
body: string;
|