@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.
- package/README.md +150 -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 +81 -43
- package/dist/errors.js +98 -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 +95 -112
- package/dist/mac/bounces.js.map +1 -1
- package/dist/mac/cleanup.d.ts +11 -25
- package/dist/mac/cleanup.js +50 -76
- package/dist/mac/cleanup.js.map +1 -1
- package/dist/mac/drafts.d.ts +13 -34
- package/dist/mac/drafts.js +95 -169
- package/dist/mac/drafts.js.map +1 -1
- package/dist/mac/folders.d.ts +10 -21
- package/dist/mac/folders.js +33 -47
- 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 +18 -38
- package/dist/mac/read.js +154 -210
- package/dist/mac/read.js.map +1 -1
- package/dist/mac/run.d.ts +35 -39
- package/dist/mac/run.js +97 -102
- package/dist/mac/run.js.map +1 -1
- package/dist/mac/scripts.d.ts +78 -86
- package/dist/mac/scripts.js +125 -115
- package/dist/mac/scripts.js.map +1 -1
- package/dist/mac/send.d.ts +10 -20
- package/dist/mac/send.js +64 -86
- 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 +75 -113
- package/dist/mac/templates.js.map +1 -1
- package/dist/mail.d.ts +77 -45
- package/dist/mail.js +166 -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 +28 -16
- package/dist/shared/attachmentMatch.js +60 -22
- 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 +12 -6
- package/dist/shared/json.js +29 -23
- package/dist/shared/json.js.map +1 -1
- package/dist/shared/locate.d.ts +39 -0
- package/dist/shared/locate.js +129 -0
- package/dist/shared/locate.js.map +1 -0
- package/dist/shared/replyBody.d.ts +42 -32
- package/dist/shared/replyBody.js +84 -71
- package/dist/shared/replyBody.js.map +1 -1
- package/dist/templateBody.d.ts +63 -0
- package/dist/{outlookTemplateSections.js → templateBody.js} +72 -72
- package/dist/templateBody.js.map +1 -0
- package/dist/types.d.ts +360 -167
- 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 +19 -23
- package/dist/windows/cleanup.js +92 -111
- package/dist/windows/cleanup.js.map +1 -1
- package/dist/windows/drafts.d.ts +16 -35
- package/dist/windows/drafts.js +167 -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 +261 -306
- package/dist/windows/read.js.map +1 -1
- package/dist/windows/run.d.ts +39 -39
- package/dist/windows/run.js +151 -111
- 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 +6 -11
- package/dist/windows/send.js +68 -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 +122 -149
- package/dist/windows/templates.js.map +1 -1
- package/package.json +4 -3
- 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/scripts.d.ts
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import type { MailFolderRef } from '../types';
|
|
1
|
+
import type { ItemFailure, MailFolderRef } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* `tell application "Microsoft Outlook"` block; binds `targetAcct`.
|
|
3
|
+
* An account as the generated AppleScript reaches it.
|
|
5
4
|
*
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* `folderIds` carries what Outlook's profile database knows about the mailbox's
|
|
6
|
+
* well-known folders — the only handle on a mailbox the dictionary publishes no
|
|
7
|
+
* account object for (see profile.ts). It is filled in for every account the
|
|
8
|
+
* profile lists, because the generated script chooses between the account
|
|
9
|
+
* object and the folder id at run time; nothing here has to predict which kinds
|
|
10
|
+
* of account a given Outlook build exposes.
|
|
12
11
|
*/
|
|
13
|
-
export
|
|
12
|
+
export interface MacAccount {
|
|
13
|
+
readonly emailAccount: string;
|
|
14
|
+
readonly folderIds?: Readonly<Record<string, number>>;
|
|
15
|
+
}
|
|
16
|
+
/** Look an address up in Outlook's profile database, for the folder ids it can add. */
|
|
17
|
+
export declare function resolveMacAccount(emailAccount: string): Promise<MacAccount>;
|
|
14
18
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* Resolve the account whose address matches into `targetAcct`, inside a
|
|
20
|
+
* `tell application "Microsoft Outlook"` block.
|
|
21
|
+
*
|
|
22
|
+
* `every account` errors even in legacy mode, so the typed classes are probed.
|
|
23
|
+
* A `whose email address is …` filter can't be used either: `email address` is
|
|
24
|
+
* also a class name, and AppleScript resolves it as one.
|
|
17
25
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
26
|
+
* A mailbox the dictionary publishes no account object for leaves `targetAcct`
|
|
27
|
+
* as `missing value` rather than failing, provided the profile gave a folder id
|
|
28
|
+
* to reach it by. `needsAccountObject` is for composing mail, which can't work
|
|
29
|
+
* without the object: the account a message is sent from can only be set from
|
|
30
|
+
* it, and a message composed without it goes out from the default mailbox.
|
|
31
|
+
*/
|
|
32
|
+
export declare function accountLookupSnippet(acct: MacAccount, needsAccountObject?: boolean): string;
|
|
33
|
+
/**
|
|
34
|
+
* Bind `variable` to one of the account's well-known folders: through the
|
|
35
|
+
* account object when the probe found one, else by the folder's own id. `mail
|
|
36
|
+
* folder id N` resolves against the application rather than an account, and N is
|
|
37
|
+
* the id Outlook's profile database records for that folder.
|
|
22
38
|
*/
|
|
23
|
-
export declare
|
|
24
|
-
/**
|
|
39
|
+
export declare function rootFolderSnippet(acct: MacAccount, term: string, variable: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Outlook for Mac's dictionary term for each well-known root, by olDefaultFolders
|
|
42
|
+
* id. Verified against the running app: the terms are NOT what the Windows names
|
|
43
|
+
* suggest — `sent mail` and `junk email` don't compile, `sent items` and `junk
|
|
44
|
+
* mail` do — and one bad term fails the whole script at compile time.
|
|
45
|
+
*/
|
|
46
|
+
export declare const MAC_ROOT_TERMS: Readonly<Record<number, string>>;
|
|
47
|
+
/** The date property a root's items carry. */
|
|
25
48
|
export declare function dateProperty(rootId: number): string;
|
|
26
49
|
/**
|
|
27
|
-
* The Windows
|
|
28
|
-
*
|
|
29
|
-
*
|
|
50
|
+
* The Windows folder-path shape (`\\mailbox\Inbox\Invoices`), assembled in
|
|
51
|
+
* TypeScript: escaping backslashes through a template literal and then an
|
|
52
|
+
* AppleScript literal is unreadable, and the parts are known here anyway.
|
|
30
53
|
*/
|
|
31
|
-
export declare function macFolderPath(emailAccount: string, rootLabel: string, segments: string[]): string;
|
|
32
|
-
/** The dictionary term for a root, or
|
|
54
|
+
export declare function macFolderPath(emailAccount: string, rootLabel: string, segments: readonly string[]): string;
|
|
55
|
+
/** The dictionary term for a root, or NOT_IMPLEMENTED naming what was asked. */
|
|
33
56
|
export declare function rootTerm(ref: MailFolderRef, folderLabel?: string): string;
|
|
34
57
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* `scopeCreated`.
|
|
58
|
+
* Resolve `scopeFolder` from `targetAcct`: a well-known root walked down through
|
|
59
|
+
* any further segments. Also binds `scopeCreated`.
|
|
38
60
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* returning the Inbox for a caller that scoped to one folder hands back the wrong
|
|
43
|
-
* emails under a name that says otherwise. `createMissing` builds the whole
|
|
44
|
-
* chain instead, so a nested destination is one call.
|
|
61
|
+
* Names compare with `is`, which is case-insensitive in AppleScript, matching
|
|
62
|
+
* the Windows walk. A missing segment fails as NOT_FOUND rather than falling
|
|
63
|
+
* back to the root; `createMissing` builds the chain instead.
|
|
45
64
|
*/
|
|
46
|
-
export declare function mailScopeSnippet(ref: MailFolderRef, folderLabel?: string, createMissing?: boolean): string;
|
|
65
|
+
export declare function mailScopeSnippet(acct: MacAccount, ref: MailFolderRef, folderLabel?: string, createMissing?: boolean): string;
|
|
47
66
|
/**
|
|
48
|
-
* The message
|
|
67
|
+
* The message id text for a script, or INVALID_REQUEST.
|
|
49
68
|
*
|
|
50
|
-
* Outlook for Mac ids are small integers; a Windows
|
|
51
|
-
*
|
|
52
|
-
*
|
|
69
|
+
* Outlook for Mac ids are small integers; a Windows EntryID is refused up front
|
|
70
|
+
* rather than left to fail as a confusing "not found", because a caller that
|
|
71
|
+
* persisted one from a Windows run needs to be told exactly that.
|
|
53
72
|
*/
|
|
54
73
|
export declare function macMessageId(entryId: string): string;
|
|
55
74
|
/**
|
|
56
|
-
* Split ids into
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* belongs in the result's `failed` list beside a genuine lookup miss — not as an
|
|
60
|
-
* exception that discards the ids that would have worked.
|
|
75
|
+
* Split ids into those a script can look up and those that can only fail. A
|
|
76
|
+
* batch reports an unusable id beside a genuine miss rather than throwing and
|
|
77
|
+
* discarding the ids that would have worked.
|
|
61
78
|
*/
|
|
62
79
|
export declare function partitionMessageIds(entryIds: readonly string[]): {
|
|
63
80
|
valid: string[];
|
|
64
|
-
invalid:
|
|
65
|
-
entryId: string;
|
|
66
|
-
error: string;
|
|
67
|
-
}[];
|
|
81
|
+
invalid: ItemFailure[];
|
|
68
82
|
};
|
|
69
83
|
/**
|
|
70
|
-
* Resolve `
|
|
71
|
-
*
|
|
72
|
-
* `message id N` resolves against the application rather than one folder, so the
|
|
73
|
-
* message is found wherever it currently sits — including a subfolder.
|
|
84
|
+
* Resolve `variable` from a message id, or fail as NOT_FOUND. `message id N`
|
|
85
|
+
* resolves against the application, so the message is found wherever it sits.
|
|
74
86
|
*/
|
|
75
87
|
export declare function messageLookupSnippet(id: string, variable?: string): string;
|
|
76
88
|
/**
|
|
77
|
-
* The sender's display name and address
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* record has to be bound first. `name` is absent when there is no display name.
|
|
89
|
+
* The sender's display name and address as `sndName` / `sndAddr`. `sender` is a
|
|
90
|
+
* record, and `address of sender of m` doesn't coerce, so the record is bound
|
|
91
|
+
* first.
|
|
81
92
|
*/
|
|
82
93
|
export declare function senderSnippet(messageVariable?: string, indent?: string): string;
|
|
83
94
|
/**
|
|
84
|
-
* Everything a reader wants off
|
|
85
|
-
* row it produces
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* Three callers share it (`readEmailBody`, `readSelectedEmail`, and the
|
|
89
|
-
* attachment resolver) and differ only in how they bind `theMsg`. They used to
|
|
90
|
-
* share it by copy: thirty lines repeated, with the `time received` → `time sent`
|
|
91
|
-
* fallback and the field order restated each time, so a dictionary fix reached
|
|
92
|
-
* one reader and not the others.
|
|
93
|
-
*
|
|
94
|
-
* `bodyText` is emitted LAST when asked for, so a stray separator in an earlier
|
|
95
|
-
* field cannot shift it.
|
|
95
|
+
* Everything a reader wants off one message bound to `theMsg`, emitted together
|
|
96
|
+
* with the row it produces (see `messageDetailFields`) so the read order and the
|
|
97
|
+
* positions the decoders index into cannot drift apart. `bodyText` is emitted
|
|
98
|
+
* LAST when asked for, so a stray separator in an earlier field can't shift it.
|
|
96
99
|
*/
|
|
97
100
|
export declare function messageDetailSnippet(withBody?: boolean, indent?: string): string;
|
|
98
|
-
/**
|
|
99
|
-
* The fields `messageDetailSnippet` fills, in row order. The decoders read them
|
|
100
|
-
* back by the positions in `MessageDetail`.
|
|
101
|
-
*/
|
|
101
|
+
/** The fields `messageDetailSnippet` fills, in row order — see `MessageDetail`. */
|
|
102
102
|
export declare function messageDetailFields(withBody?: boolean): string[];
|
|
103
|
-
/** Where each of those fields lands in the
|
|
103
|
+
/** Where each of those fields lands in the row. */
|
|
104
104
|
export declare const MessageDetail: {
|
|
105
105
|
readonly id: 0;
|
|
106
106
|
readonly subject: 1;
|
|
@@ -111,27 +111,19 @@ export declare const MessageDetail: {
|
|
|
111
111
|
readonly body: 6;
|
|
112
112
|
};
|
|
113
113
|
/**
|
|
114
|
-
* The first recipient's name and address
|
|
115
|
-
* outgoing mail reports in place of a sender
|
|
116
|
-
* contract for Sent Items (a folder of mail from yourself is unreadable).
|
|
114
|
+
* The first recipient's name and address as `sndName` / `sndAddr` — what
|
|
115
|
+
* outgoing mail reports in place of a sender.
|
|
117
116
|
*/
|
|
118
117
|
export declare function firstRecipientSnippet(messageVariable?: string, indent?: string): string;
|
|
119
|
-
/**
|
|
120
|
-
* Every SMTP address a message was addressed to, as the list `addrList`.
|
|
121
|
-
*
|
|
122
|
-
* `every recipient` covers To, CC and BCC — the full set, which is the whole
|
|
123
|
-
* point of readSentRecipientGroups.
|
|
124
|
-
*/
|
|
118
|
+
/** Every address a message was sent to — To, CC and BCC — as the list `addrList`. */
|
|
125
119
|
export declare function allRecipientsSnippet(messageVariable?: string, indent?: string): string;
|
|
126
120
|
/**
|
|
127
|
-
* Recursive
|
|
128
|
-
*
|
|
129
|
-
* resolve a template folder anywhere in the mailbox tree.
|
|
121
|
+
* Recursive, case-insensitive, depth-capped folder search from `startFolder` —
|
|
122
|
+
* the macOS counterpart of the Windows Find-FolderByName.
|
|
130
123
|
*/
|
|
131
124
|
export declare const FIND_FOLDER_HANDLER = "\non findFolderByName(startFolder, wantedName, depth)\n tell application \"Microsoft Outlook\"\n set subs to mail folders of startFolder\n end tell\n repeat with f in subs\n if (name of f as string) is wantedName then return f\n end repeat\n if depth is less than or equal to 1 then return missing value\n repeat with f in subs\n set hit to my findFolderByName(f, wantedName, depth - 1)\n if hit is not missing value then return hit\n end repeat\n return missing value\nend findFolderByName\n";
|
|
132
125
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* each class is probed independently and failures are ignored.
|
|
126
|
+
* Enumerate the accounts, probing each class separately: legacy Outlook errors
|
|
127
|
+
* on `every account`, and New Outlook returns empty lists for the classes.
|
|
136
128
|
*/
|
|
137
129
|
export declare const LIST_ACCOUNTS_SNIPPET = "\nset acctList to {}\ntell application \"Microsoft Outlook\"\n repeat with acctClass in {\"exchange\", \"imap\", \"pop\"}\n try\n if (acctClass as string) is \"exchange\" then\n set accts to exchange accounts\n else if (acctClass as string) is \"imap\" then\n set accts to imap accounts\n else\n set accts to pop accounts\n end if\n repeat with a in accts\n try\n set end of acctList to (email address of a as string)\n end try\n end repeat\n end try\n end repeat\nend tell\n";
|
package/dist/mac/scripts.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LIST_ACCOUNTS_SNIPPET = exports.FIND_FOLDER_HANDLER = exports.MessageDetail = exports.MAC_ROOT_TERMS = void 0;
|
|
4
|
+
exports.resolveMacAccount = resolveMacAccount;
|
|
4
5
|
exports.accountLookupSnippet = accountLookupSnippet;
|
|
6
|
+
exports.rootFolderSnippet = rootFolderSnippet;
|
|
5
7
|
exports.dateProperty = dateProperty;
|
|
6
8
|
exports.macFolderPath = macFolderPath;
|
|
7
9
|
exports.rootTerm = rootTerm;
|
|
@@ -16,125 +18,161 @@ exports.firstRecipientSnippet = firstRecipientSnippet;
|
|
|
16
18
|
exports.allRecipientsSnippet = allRecipientsSnippet;
|
|
17
19
|
// The AppleScript fragments more than one macOS operation is built from.
|
|
18
20
|
const run_1 = require("./run");
|
|
21
|
+
const profile_1 = require("./profile");
|
|
19
22
|
const errors_1 = require("../errors");
|
|
20
23
|
const mail_1 = require("../mail");
|
|
24
|
+
/** Look an address up in Outlook's profile database, for the folder ids it can add. */
|
|
25
|
+
async function resolveMacAccount(emailAccount) {
|
|
26
|
+
const wanted = emailAccount.trim().toLowerCase();
|
|
27
|
+
const found = (await (0, profile_1.readProfileAccounts)())
|
|
28
|
+
.find(account => account.emailAccount.trim().toLowerCase() === wanted);
|
|
29
|
+
return found ? { emailAccount, folderIds: found.folderIds } : { emailAccount };
|
|
30
|
+
}
|
|
21
31
|
/**
|
|
22
|
-
* Resolve the account whose
|
|
23
|
-
* `tell application "Microsoft Outlook"` block
|
|
32
|
+
* Resolve the account whose address matches into `targetAcct`, inside a
|
|
33
|
+
* `tell application "Microsoft Outlook"` block.
|
|
24
34
|
*
|
|
25
|
-
* `every account` errors even in legacy mode, so
|
|
26
|
-
* `whose email address is
|
|
27
|
-
* also a class name, and AppleScript resolves it as one
|
|
35
|
+
* `every account` errors even in legacy mode, so the typed classes are probed.
|
|
36
|
+
* A `whose email address is …` filter can't be used either: `email address` is
|
|
37
|
+
* also a class name, and AppleScript resolves it as one.
|
|
28
38
|
*
|
|
29
|
-
*
|
|
30
|
-
* `
|
|
39
|
+
* A mailbox the dictionary publishes no account object for leaves `targetAcct`
|
|
40
|
+
* as `missing value` rather than failing, provided the profile gave a folder id
|
|
41
|
+
* to reach it by. `needsAccountObject` is for composing mail, which can't work
|
|
42
|
+
* without the object: the account a message is sent from can only be set from
|
|
43
|
+
* it, and a message composed without it goes out from the default mailbox.
|
|
31
44
|
*/
|
|
32
|
-
function accountLookupSnippet(
|
|
33
|
-
|
|
45
|
+
function accountLookupSnippet(acct, needsAccountObject = false) {
|
|
46
|
+
const probe = ` set targetAcct to missing value
|
|
34
47
|
try
|
|
35
48
|
repeat with a in (exchange accounts & imap accounts & pop accounts)
|
|
36
|
-
if (email address of a as string) is
|
|
49
|
+
if (email address of a as string) is ${(0, run_1.asString)(acct.emailAccount)} then
|
|
37
50
|
set targetAcct to a
|
|
38
51
|
exit repeat
|
|
39
52
|
end if
|
|
40
53
|
end repeat
|
|
41
|
-
end try
|
|
42
|
-
if
|
|
54
|
+
end try`;
|
|
55
|
+
if (acct.folderIds && !needsAccountObject)
|
|
56
|
+
return probe;
|
|
57
|
+
const complaint = acct.folderIds
|
|
58
|
+
? `${(0, errors_1.failureTag)('INVALID_REQUEST')}Outlook publishes no account object for '${acct.emailAccount}', `
|
|
59
|
+
+ 'so the account a message is sent from cannot be set. Its folders can be read; mail cannot be composed from it.'
|
|
60
|
+
: `${(0, errors_1.failureTag)('ACCOUNT_NOT_FOUND')}Account '${acct.emailAccount}' not found in Outlook.`;
|
|
61
|
+
return `${probe}
|
|
62
|
+
if targetAcct is missing value then error ${(0, run_1.asString)(complaint)}`;
|
|
43
63
|
}
|
|
44
64
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
* Bind `variable` to one of the account's well-known folders: through the
|
|
66
|
+
* account object when the probe found one, else by the folder's own id. `mail
|
|
67
|
+
* folder id N` resolves against the application rather than an account, and N is
|
|
68
|
+
* the id Outlook's profile database records for that folder.
|
|
69
|
+
*/
|
|
70
|
+
function rootFolderSnippet(acct, term, variable) {
|
|
71
|
+
const viaAccount = ` set ${variable} to ${term} of targetAcct`;
|
|
72
|
+
const id = acct.folderIds?.[term];
|
|
73
|
+
if (id !== undefined) {
|
|
74
|
+
return ` if targetAcct is missing value then
|
|
75
|
+
set ${variable} to mail folder id ${id}
|
|
76
|
+
else
|
|
77
|
+
${viaAccount}
|
|
78
|
+
end if`;
|
|
79
|
+
}
|
|
80
|
+
// The profile listed the mailbox but not this root, so the probe is the only
|
|
81
|
+
// way in — and it may have come up empty. Name the folder out of reach
|
|
82
|
+
// rather than let `<term> of missing value` say it.
|
|
83
|
+
if (acct.folderIds) {
|
|
84
|
+
const complaint = `${(0, errors_1.failureTag)('NOT_FOUND', 'folder')}Account '${acct.emailAccount}' has no ${term} folder AppleScript can reach.`;
|
|
85
|
+
return ` if targetAcct is missing value then error ${(0, run_1.asString)(complaint)}
|
|
86
|
+
${viaAccount}`;
|
|
87
|
+
}
|
|
88
|
+
return viaAccount;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Outlook for Mac's dictionary term for each well-known root, by olDefaultFolders
|
|
92
|
+
* id. Verified against the running app: the terms are NOT what the Windows names
|
|
93
|
+
* suggest — `sent mail` and `junk email` don't compile, `sent items` and `junk
|
|
94
|
+
* mail` do — and one bad term fails the whole script at compile time.
|
|
52
95
|
*/
|
|
53
96
|
exports.MAC_ROOT_TERMS = {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
97
|
+
[mail_1.FolderId.Inbox]: 'inbox',
|
|
98
|
+
[mail_1.FolderId.SentMail]: 'sent items',
|
|
99
|
+
[mail_1.FolderId.Drafts]: 'drafts',
|
|
100
|
+
[mail_1.FolderId.DeletedItems]: 'deleted items',
|
|
101
|
+
[mail_1.FolderId.Outbox]: 'outbox',
|
|
102
|
+
[mail_1.FolderId.Junk]: 'junk mail',
|
|
60
103
|
};
|
|
61
|
-
/** The date property a
|
|
104
|
+
/** The date property a root's items carry. */
|
|
62
105
|
function dateProperty(rootId) {
|
|
63
106
|
return (0, mail_1.isOutgoingRoot)(rootId) ? 'time sent' : 'time received';
|
|
64
107
|
}
|
|
65
108
|
/**
|
|
66
|
-
* The Windows
|
|
67
|
-
*
|
|
68
|
-
*
|
|
109
|
+
* The Windows folder-path shape (`\\mailbox\Inbox\Invoices`), assembled in
|
|
110
|
+
* TypeScript: escaping backslashes through a template literal and then an
|
|
111
|
+
* AppleScript literal is unreadable, and the parts are known here anyway.
|
|
69
112
|
*/
|
|
70
113
|
function macFolderPath(emailAccount, rootLabel, segments) {
|
|
71
114
|
return ['\\\\' + emailAccount, rootLabel, ...segments].join('\\');
|
|
72
115
|
}
|
|
73
|
-
/** The dictionary term for a root, or
|
|
116
|
+
/** The dictionary term for a root, or NOT_IMPLEMENTED naming what was asked. */
|
|
74
117
|
function rootTerm(ref, folderLabel = '') {
|
|
75
118
|
const term = exports.MAC_ROOT_TERMS[ref.rootId];
|
|
76
119
|
if (!term) {
|
|
77
120
|
const asked = folderLabel ? ` (asked for '${folderLabel}')` : '';
|
|
78
|
-
throw new errors_1.NotImplementedError(`
|
|
121
|
+
throw new errors_1.NotImplementedError(`Reading the '${ref.rootLabel}' folder${asked}`, `macOS, whose readable roots are ${Object.values(exports.MAC_ROOT_TERMS).join(', ')}`);
|
|
79
122
|
}
|
|
80
123
|
return term;
|
|
81
124
|
}
|
|
82
125
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* `scopeCreated`.
|
|
126
|
+
* Resolve `scopeFolder` from `targetAcct`: a well-known root walked down through
|
|
127
|
+
* any further segments. Also binds `scopeCreated`.
|
|
86
128
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* returning the Inbox for a caller that scoped to one folder hands back the wrong
|
|
91
|
-
* emails under a name that says otherwise. `createMissing` builds the whole
|
|
92
|
-
* chain instead, so a nested destination is one call.
|
|
129
|
+
* Names compare with `is`, which is case-insensitive in AppleScript, matching
|
|
130
|
+
* the Windows walk. A missing segment fails as NOT_FOUND rather than falling
|
|
131
|
+
* back to the root; `createMissing` builds the chain instead.
|
|
93
132
|
*/
|
|
94
|
-
function mailScopeSnippet(ref, folderLabel = '', createMissing = false) {
|
|
133
|
+
function mailScopeSnippet(acct, ref, folderLabel = '', createMissing = false) {
|
|
95
134
|
const term = rootTerm(ref, folderLabel);
|
|
96
|
-
const walk = ref.segments.map(
|
|
135
|
+
const walk = ref.segments.map(segment => {
|
|
136
|
+
const complaint = `${(0, errors_1.failureTag)('NOT_FOUND', 'folder')}Folder '${segment}' not found under '${ref.rootLabel}'.`;
|
|
137
|
+
const create = createMissing
|
|
138
|
+
? ` set foundFolder to (make new mail folder at scopeFolder with properties {name:${(0, run_1.asString)(segment)}})
|
|
139
|
+
set scopeCreated to true`
|
|
140
|
+
: ` error ${(0, run_1.asString)(complaint)}`;
|
|
141
|
+
return `
|
|
97
142
|
set foundFolder to missing value
|
|
98
143
|
repeat with sf in (mail folders of scopeFolder)
|
|
99
|
-
if (name of sf as string) is
|
|
144
|
+
if (name of sf as string) is ${(0, run_1.asString)(segment)} then
|
|
100
145
|
set foundFolder to sf
|
|
101
146
|
exit repeat
|
|
102
147
|
end if
|
|
103
148
|
end repeat
|
|
104
149
|
if foundFolder is missing value then
|
|
105
|
-
|
|
106
|
-
set foundFolder to (make new mail folder at scopeFolder with properties {name:"${(0, run_1.asEscape)(seg)}"})
|
|
107
|
-
set scopeCreated to true
|
|
108
|
-
else
|
|
109
|
-
error "Folder '${(0, run_1.asEscape)(seg)}' not found under '${(0, run_1.asEscape)(ref.rootLabel)}'"
|
|
110
|
-
end if
|
|
150
|
+
${create}
|
|
111
151
|
end if
|
|
112
|
-
set scopeFolder to foundFolder
|
|
152
|
+
set scopeFolder to foundFolder`;
|
|
153
|
+
}).join('');
|
|
113
154
|
return ` set scopeCreated to false
|
|
114
|
-
|
|
155
|
+
${rootFolderSnippet(acct, term, 'scopeFolder')}${walk}`;
|
|
115
156
|
}
|
|
116
157
|
/**
|
|
117
|
-
* The message
|
|
158
|
+
* The message id text for a script, or INVALID_REQUEST.
|
|
118
159
|
*
|
|
119
|
-
* Outlook for Mac ids are small integers; a Windows
|
|
120
|
-
*
|
|
121
|
-
*
|
|
160
|
+
* Outlook for Mac ids are small integers; a Windows EntryID is refused up front
|
|
161
|
+
* rather than left to fail as a confusing "not found", because a caller that
|
|
162
|
+
* persisted one from a Windows run needs to be told exactly that.
|
|
122
163
|
*/
|
|
123
164
|
function macMessageId(entryId) {
|
|
124
165
|
const id = String(entryId ?? '').trim();
|
|
125
166
|
if (!/^\d+$/.test(id)) {
|
|
126
167
|
throw new errors_1.InvalidRequestError(`'${entryId}' is not an Outlook for Mac message id. Mac ids are small integers `
|
|
127
|
-
+
|
|
128
|
-
+ `EntryID cannot be resolved here.`);
|
|
168
|
+
+ '(e.g. "1263") listed on this machine; a Windows EntryID cannot be resolved here.');
|
|
129
169
|
}
|
|
130
170
|
return id;
|
|
131
171
|
}
|
|
132
172
|
/**
|
|
133
|
-
* Split ids into
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* belongs in the result's `failed` list beside a genuine lookup miss — not as an
|
|
137
|
-
* exception that discards the ids that would have worked.
|
|
173
|
+
* Split ids into those a script can look up and those that can only fail. A
|
|
174
|
+
* batch reports an unusable id beside a genuine miss rather than throwing and
|
|
175
|
+
* discarding the ids that would have worked.
|
|
138
176
|
*/
|
|
139
177
|
function partitionMessageIds(entryIds) {
|
|
140
178
|
const valid = [];
|
|
@@ -144,29 +182,27 @@ function partitionMessageIds(entryIds) {
|
|
|
144
182
|
valid.push(macMessageId(entryId));
|
|
145
183
|
}
|
|
146
184
|
catch (error) {
|
|
147
|
-
invalid.push({ entryId: String(entryId), error: error.message });
|
|
185
|
+
invalid.push({ entryId: String(entryId), subject: '', error: error.message });
|
|
148
186
|
}
|
|
149
187
|
}
|
|
150
188
|
return { valid, invalid };
|
|
151
189
|
}
|
|
152
190
|
/**
|
|
153
|
-
* Resolve `
|
|
154
|
-
*
|
|
155
|
-
* `message id N` resolves against the application rather than one folder, so the
|
|
156
|
-
* message is found wherever it currently sits — including a subfolder.
|
|
191
|
+
* Resolve `variable` from a message id, or fail as NOT_FOUND. `message id N`
|
|
192
|
+
* resolves against the application, so the message is found wherever it sits.
|
|
157
193
|
*/
|
|
158
194
|
function messageLookupSnippet(id, variable = 'theMsg') {
|
|
195
|
+
const complaint = `${(0, errors_1.failureTag)('NOT_FOUND', 'email')}No email found for message id '${id}'. It may have been deleted - list the mail again for a current id.`;
|
|
159
196
|
return ` set ${variable} to missing value
|
|
160
197
|
try
|
|
161
198
|
set ${variable} to message id ${id}
|
|
162
199
|
end try
|
|
163
|
-
if ${variable} is missing value then error
|
|
200
|
+
if ${variable} is missing value then error ${(0, run_1.asString)(complaint)}`;
|
|
164
201
|
}
|
|
165
202
|
/**
|
|
166
|
-
* The sender's display name and address
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* record has to be bound first. `name` is absent when there is no display name.
|
|
203
|
+
* The sender's display name and address as `sndName` / `sndAddr`. `sender` is a
|
|
204
|
+
* record, and `address of sender of m` doesn't coerce, so the record is bound
|
|
205
|
+
* first.
|
|
170
206
|
*/
|
|
171
207
|
function senderSnippet(messageVariable = 'theMsg', indent = ' ') {
|
|
172
208
|
return `${indent}set sndName to ""
|
|
@@ -182,18 +218,10 @@ ${indent} end try
|
|
|
182
218
|
${indent}end try`;
|
|
183
219
|
}
|
|
184
220
|
/**
|
|
185
|
-
* Everything a reader wants off
|
|
186
|
-
* row it produces
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* Three callers share it (`readEmailBody`, `readSelectedEmail`, and the
|
|
190
|
-
* attachment resolver) and differ only in how they bind `theMsg`. They used to
|
|
191
|
-
* share it by copy: thirty lines repeated, with the `time received` → `time sent`
|
|
192
|
-
* fallback and the field order restated each time, so a dictionary fix reached
|
|
193
|
-
* one reader and not the others.
|
|
194
|
-
*
|
|
195
|
-
* `bodyText` is emitted LAST when asked for, so a stray separator in an earlier
|
|
196
|
-
* field cannot shift it.
|
|
221
|
+
* Everything a reader wants off one message bound to `theMsg`, emitted together
|
|
222
|
+
* with the row it produces (see `messageDetailFields`) so the read order and the
|
|
223
|
+
* positions the decoders index into cannot drift apart. `bodyText` is emitted
|
|
224
|
+
* LAST when asked for, so a stray separator in an earlier field can't shift it.
|
|
197
225
|
*/
|
|
198
226
|
function messageDetailSnippet(withBody = false, indent = ' ') {
|
|
199
227
|
return `${indent}set subj to ""
|
|
@@ -218,24 +246,14 @@ ${indent}try
|
|
|
218
246
|
${indent} set bodyText to (plain text content of theMsg) as string
|
|
219
247
|
${indent}end try` : '');
|
|
220
248
|
}
|
|
221
|
-
/**
|
|
222
|
-
* The fields `messageDetailSnippet` fills, in row order. The decoders read them
|
|
223
|
-
* back by the positions in `MessageDetail`.
|
|
224
|
-
*/
|
|
249
|
+
/** The fields `messageDetailSnippet` fills, in row order — see `MessageDetail`. */
|
|
225
250
|
function messageDetailFields(withBody = false) {
|
|
226
|
-
const fields = [
|
|
227
|
-
'(id of theMsg as string)',
|
|
228
|
-
'subj',
|
|
229
|
-
'sndName',
|
|
230
|
-
'sndAddr',
|
|
231
|
-
'recvd',
|
|
232
|
-
'my sanitizeList(attNames)',
|
|
233
|
-
];
|
|
251
|
+
const fields = ['(id of theMsg as string)', 'subj', 'sndName', 'sndAddr', 'recvd', 'my sanitizeList(attNames)'];
|
|
234
252
|
if (withBody)
|
|
235
253
|
fields.push('bodyText');
|
|
236
254
|
return fields;
|
|
237
255
|
}
|
|
238
|
-
/** Where each of those fields lands in the
|
|
256
|
+
/** Where each of those fields lands in the row. */
|
|
239
257
|
exports.MessageDetail = {
|
|
240
258
|
id: 0,
|
|
241
259
|
subject: 1,
|
|
@@ -246,9 +264,8 @@ exports.MessageDetail = {
|
|
|
246
264
|
body: 6,
|
|
247
265
|
};
|
|
248
266
|
/**
|
|
249
|
-
* The first recipient's name and address
|
|
250
|
-
* outgoing mail reports in place of a sender
|
|
251
|
-
* contract for Sent Items (a folder of mail from yourself is unreadable).
|
|
267
|
+
* The first recipient's name and address as `sndName` / `sndAddr` — what
|
|
268
|
+
* outgoing mail reports in place of a sender.
|
|
252
269
|
*/
|
|
253
270
|
function firstRecipientSnippet(messageVariable = 'theMsg', indent = ' ') {
|
|
254
271
|
return `${indent}set sndName to ""
|
|
@@ -266,20 +283,15 @@ ${indent} end try
|
|
|
266
283
|
${indent} end if
|
|
267
284
|
${indent}end try`;
|
|
268
285
|
}
|
|
269
|
-
/**
|
|
270
|
-
* Every SMTP address a message was addressed to, as the list `addrList`.
|
|
271
|
-
*
|
|
272
|
-
* `every recipient` covers To, CC and BCC — the full set, which is the whole
|
|
273
|
-
* point of readSentRecipientGroups.
|
|
274
|
-
*/
|
|
286
|
+
/** Every address a message was sent to — To, CC and BCC — as the list `addrList`. */
|
|
275
287
|
function allRecipientsSnippet(messageVariable = 'theMsg', indent = ' ') {
|
|
276
288
|
return `${indent}set addrList to {}
|
|
277
289
|
${indent}try
|
|
278
290
|
${indent} repeat with r in (every recipient of ${messageVariable})
|
|
279
291
|
${indent} try
|
|
280
|
-
${indent} -- The record
|
|
281
|
-
${indent} -- 'address of (email address of r)'
|
|
282
|
-
${indent} -- inside the try as an empty
|
|
292
|
+
${indent} -- The record is bound before its field is read: a nested
|
|
293
|
+
${indent} -- 'address of (email address of r)' doesn't coerce, and fails
|
|
294
|
+
${indent} -- inside the try as an empty list rather than an error.
|
|
283
295
|
${indent} set ea to email address of r
|
|
284
296
|
${indent} set oneAddr to (address of ea) as string
|
|
285
297
|
${indent} if oneAddr is not "" then set end of addrList to oneAddr
|
|
@@ -288,9 +300,8 @@ ${indent} end repeat
|
|
|
288
300
|
${indent}end try`;
|
|
289
301
|
}
|
|
290
302
|
/**
|
|
291
|
-
* Recursive
|
|
292
|
-
*
|
|
293
|
-
* resolve a template folder anywhere in the mailbox tree.
|
|
303
|
+
* Recursive, case-insensitive, depth-capped folder search from `startFolder` —
|
|
304
|
+
* the macOS counterpart of the Windows Find-FolderByName.
|
|
294
305
|
*/
|
|
295
306
|
exports.FIND_FOLDER_HANDLER = `
|
|
296
307
|
on findFolderByName(startFolder, wantedName, depth)
|
|
@@ -309,9 +320,8 @@ on findFolderByName(startFolder, wantedName, depth)
|
|
|
309
320
|
end findFolderByName
|
|
310
321
|
`;
|
|
311
322
|
/**
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* each class is probed independently and failures are ignored.
|
|
323
|
+
* Enumerate the accounts, probing each class separately: legacy Outlook errors
|
|
324
|
+
* on `every account`, and New Outlook returns empty lists for the classes.
|
|
315
325
|
*/
|
|
316
326
|
exports.LIST_ACCOUNTS_SNIPPET = `
|
|
317
327
|
set acctList to {}
|