apple-mail-mcp 1.1.1 → 1.2.1
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 +73 -14
- package/build/index.js +98 -25
- package/build/services/appleMailManager.d.ts +17 -3
- package/build/services/appleMailManager.d.ts.map +1 -1
- package/build/services/appleMailManager.js +144 -25
- package/build/types.d.ts +20 -0
- package/build/types.d.ts.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -84,8 +84,9 @@ On first use, macOS will ask for permission to automate Mail.app. Click "OK" to
|
|
|
84
84
|
| **List Messages** | List messages with pagination, sender filter, date display |
|
|
85
85
|
| **Search Messages** | Search by sender, subject, content, date range, read/flagged status — across all accounts |
|
|
86
86
|
| **Read Messages** | Get full email content (plain text or HTML) |
|
|
87
|
-
| **Send Email** | Compose and send new emails |
|
|
88
|
-
| **
|
|
87
|
+
| **Send Email** | Compose and send new emails (with optional file attachments) |
|
|
88
|
+
| **Send Serial Email** | Mail merge — send personalized emails to a list of recipients with {{placeholder}} support |
|
|
89
|
+
| **Create Draft** | Save emails to Drafts folder (with optional file attachments) |
|
|
89
90
|
| **Reply** | Reply to messages (with reply-all support) |
|
|
90
91
|
| **Forward** | Forward messages to new recipients |
|
|
91
92
|
| **Mark Read/Unread** | Change read status (single or batch) |
|
|
@@ -190,6 +191,7 @@ Send a new email immediately.
|
|
|
190
191
|
| `cc` | string[] | No | CC recipients |
|
|
191
192
|
| `bcc` | string[] | No | BCC recipients |
|
|
192
193
|
| `account` | string | No | Send from specific account |
|
|
194
|
+
| `attachments` | string[] | No | Absolute file paths to attach, max 20 files (e.g., `["/Users/me/report.pdf"]`) |
|
|
193
195
|
|
|
194
196
|
**Example:**
|
|
195
197
|
```json
|
|
@@ -197,12 +199,48 @@ Send a new email immediately.
|
|
|
197
199
|
"to": ["colleague@company.com"],
|
|
198
200
|
"subject": "Meeting Tomorrow",
|
|
199
201
|
"body": "Hi, just confirming our meeting at 2pm tomorrow.",
|
|
200
|
-
"account": "Work"
|
|
202
|
+
"account": "Work",
|
|
203
|
+
"attachments": ["/Users/me/Documents/agenda.pdf"]
|
|
201
204
|
}
|
|
202
205
|
```
|
|
203
206
|
|
|
204
207
|
---
|
|
205
208
|
|
|
209
|
+
#### `send-serial-email`
|
|
210
|
+
|
|
211
|
+
Send individual personalized emails to a list of recipients (mail merge). Each recipient receives their own email — recipients don't see each other. Supports `{{placeholder}}` tokens in both subject and body.
|
|
212
|
+
|
|
213
|
+
| Parameter | Type | Required | Description |
|
|
214
|
+
|-----------|------|----------|-------------|
|
|
215
|
+
| `recipients` | object[] | Yes | List of recipients, max 100 (see below) |
|
|
216
|
+
| `subject` | string | Yes | Email subject — use `{{Key}}` for placeholders |
|
|
217
|
+
| `body` | string | Yes | Email body — use `{{Key}}` for placeholders |
|
|
218
|
+
| `account` | string | No | Send from specific account |
|
|
219
|
+
| `delayMs` | number | No | Delay between sends in ms (default: 500, max 10000) |
|
|
220
|
+
|
|
221
|
+
Each recipient object:
|
|
222
|
+
|
|
223
|
+
| Field | Type | Required | Description |
|
|
224
|
+
|-------|------|----------|-------------|
|
|
225
|
+
| `email` | string | Yes | Recipient email address |
|
|
226
|
+
| `variables` | object | Yes | Key-value pairs for placeholder replacement |
|
|
227
|
+
|
|
228
|
+
**Example:**
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"recipients": [
|
|
232
|
+
{ "email": "alice@example.com", "variables": { "Name": "Alice", "Company": "Acme" } },
|
|
233
|
+
{ "email": "bob@example.com", "variables": { "Name": "Bob", "Company": "Globex" } }
|
|
234
|
+
],
|
|
235
|
+
"subject": "Hello {{Name}}!",
|
|
236
|
+
"body": "Dear {{Name}},\n\nGreat to connect about {{Company}}.\n\nBest regards"
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Returns:** Per-recipient success/failure results with a summary count.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
206
244
|
#### `create-draft`
|
|
207
245
|
|
|
208
246
|
Save an email to Drafts without sending.
|
|
@@ -215,6 +253,7 @@ Save an email to Drafts without sending.
|
|
|
215
253
|
| `cc` | string[] | No | CC recipients |
|
|
216
254
|
| `bcc` | string[] | No | BCC recipients |
|
|
217
255
|
| `account` | string | No | Account for draft |
|
|
256
|
+
| `attachments` | string[] | No | Absolute file paths to attach, max 20 files |
|
|
218
257
|
|
|
219
258
|
**Returns:** Confirmation that draft was created.
|
|
220
259
|
|
|
@@ -332,19 +371,19 @@ Save a message attachment to disk.
|
|
|
332
371
|
|
|
333
372
|
### Batch Operations
|
|
334
373
|
|
|
335
|
-
All batch operations accept an array of message IDs and return per-item success/failure results.
|
|
374
|
+
All batch operations accept an array of message IDs (max 100 per batch) and return per-item success/failure results.
|
|
336
375
|
|
|
337
376
|
#### `batch-delete-messages`
|
|
338
377
|
|
|
339
378
|
| Parameter | Type | Required | Description |
|
|
340
379
|
|-----------|------|----------|-------------|
|
|
341
|
-
| `ids` | string[] | Yes | Message IDs to delete |
|
|
380
|
+
| `ids` | string[] | Yes | Message IDs to delete (max 100) |
|
|
342
381
|
|
|
343
382
|
#### `batch-move-messages`
|
|
344
383
|
|
|
345
384
|
| Parameter | Type | Required | Description |
|
|
346
385
|
|-----------|------|----------|-------------|
|
|
347
|
-
| `ids` | string[] | Yes | Message IDs to move |
|
|
386
|
+
| `ids` | string[] | Yes | Message IDs to move (max 100) |
|
|
348
387
|
| `mailbox` | string | Yes | Destination mailbox |
|
|
349
388
|
| `account` | string | No | Account containing mailbox |
|
|
350
389
|
|
|
@@ -352,13 +391,13 @@ All batch operations accept an array of message IDs and return per-item success/
|
|
|
352
391
|
|
|
353
392
|
| Parameter | Type | Required | Description |
|
|
354
393
|
|-----------|------|----------|-------------|
|
|
355
|
-
| `ids` | string[] | Yes | Message IDs |
|
|
394
|
+
| `ids` | string[] | Yes | Message IDs (max 100) |
|
|
356
395
|
|
|
357
396
|
#### `batch-flag-messages` / `batch-unflag-messages`
|
|
358
397
|
|
|
359
398
|
| Parameter | Type | Required | Description |
|
|
360
399
|
|-----------|------|----------|-------------|
|
|
361
|
-
| `ids` | string[] | Yes | Message IDs |
|
|
400
|
+
| `ids` | string[] | Yes | Message IDs (max 100) |
|
|
362
401
|
|
|
363
402
|
---
|
|
364
403
|
|
|
@@ -606,6 +645,19 @@ User: "Send it"
|
|
|
606
645
|
AI: [User opens Mail.app and sends manually, or AI calls send-email]
|
|
607
646
|
```
|
|
608
647
|
|
|
648
|
+
### Sending Personalized Emails (Mail Merge)
|
|
649
|
+
|
|
650
|
+
```
|
|
651
|
+
User: "Send a personalized email to Alice (alice@acme.com), Bob (bob@globex.com),
|
|
652
|
+
and Carol (carol@initech.com). Subject: 'Project Update for {{Company}}',
|
|
653
|
+
Body: 'Hi {{Name}}, here is the latest update for {{Company}}.'"
|
|
654
|
+
AI: [calls send-serial-email with recipients, subject template, and body template]
|
|
655
|
+
"Successfully sent 3 email(s):
|
|
656
|
+
- alice@acme.com: sent
|
|
657
|
+
- bob@globex.com: sent
|
|
658
|
+
- carol@initech.com: sent"
|
|
659
|
+
```
|
|
660
|
+
|
|
609
661
|
### Organizing Messages
|
|
610
662
|
|
|
611
663
|
```
|
|
@@ -663,9 +715,14 @@ If installed from source, use this configuration:
|
|
|
663
715
|
|------------|--------|
|
|
664
716
|
| macOS only | Apple Mail and AppleScript are macOS-specific |
|
|
665
717
|
| No sending HTML email | Emails are sent as plain text; reading HTML content is supported |
|
|
666
|
-
|
|
|
718
|
+
| Attachments require absolute paths | File attachments must use full absolute paths (e.g., `/Users/me/file.pdf`) |
|
|
667
719
|
| No smart mailboxes | Cannot access Smart Mailboxes via AppleScript |
|
|
668
720
|
| In-memory templates | Email templates are not persisted across server restarts |
|
|
721
|
+
| Numeric-only message IDs | Message IDs must contain only digits (validated by schema) |
|
|
722
|
+
| Batch size cap | Batch operations are limited to 100 messages per request |
|
|
723
|
+
| Date filter format | Date filters accept alphanumeric characters and safe punctuation only |
|
|
724
|
+
| Attachment save path restrictions | `save-attachment` only allows saving to home directory, `/tmp`, `/private/tmp`, and `/Volumes`; path traversal is blocked |
|
|
725
|
+
| Attachment count limit | `send-email` and `create-draft` accept a maximum of 20 file attachments |
|
|
669
726
|
|
|
670
727
|
### Backslash Escaping (Important for AI Agents)
|
|
671
728
|
|
|
@@ -724,11 +781,13 @@ The `\\\\` in JSON becomes `\\` in the actual string, which represents a single
|
|
|
724
781
|
## Development
|
|
725
782
|
|
|
726
783
|
```bash
|
|
727
|
-
npm install
|
|
728
|
-
npm run build
|
|
729
|
-
npm test
|
|
730
|
-
npm run
|
|
731
|
-
npm run
|
|
784
|
+
npm install # Install dependencies
|
|
785
|
+
npm run build # Compile TypeScript
|
|
786
|
+
npm test # Run unit tests
|
|
787
|
+
npm run test:integration # Run integration tests (requires Mail.app)
|
|
788
|
+
npm run test:all # Run all tests (unit + integration)
|
|
789
|
+
npm run lint # Check code style
|
|
790
|
+
npm run format # Format code
|
|
732
791
|
```
|
|
733
792
|
|
|
734
793
|
---
|
package/build/index.js
CHANGED
|
@@ -24,6 +24,23 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
24
24
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
25
|
import { z } from "zod";
|
|
26
26
|
import { AppleMailManager } from "./services/appleMailManager.js";
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Shared Validation Schemas
|
|
29
|
+
// =============================================================================
|
|
30
|
+
/** Message IDs in Apple Mail are always numeric. Enforce this at the schema level
|
|
31
|
+
* to prevent AppleScript injection via the `whose id is ${id}` interpolation. */
|
|
32
|
+
const MESSAGE_ID_SCHEMA = z.string().regex(/^\d+$/, "Message ID must be numeric");
|
|
33
|
+
/** Batch operations are capped to prevent unbounded loops / DoS. */
|
|
34
|
+
const BATCH_IDS_SCHEMA = z
|
|
35
|
+
.array(MESSAGE_ID_SCHEMA)
|
|
36
|
+
.min(1, "At least one message ID is required")
|
|
37
|
+
.max(100, "Cannot process more than 100 messages in a single batch");
|
|
38
|
+
/** Date filter strings must look like natural-language dates (e.g. "March 1, 2026").
|
|
39
|
+
* Block characters that could escape an AppleScript `date "..."` literal. */
|
|
40
|
+
const DATE_FILTER_SCHEMA = z
|
|
41
|
+
.string()
|
|
42
|
+
.regex(/^[a-zA-Z0-9 ,/\-:]+$/, "Date must contain only alphanumeric characters, spaces, commas, slashes, hyphens, and colons")
|
|
43
|
+
.optional();
|
|
27
44
|
// Read version from package.json to keep it in sync
|
|
28
45
|
const require = createRequire(import.meta.url);
|
|
29
46
|
const { version } = require("../package.json");
|
|
@@ -89,8 +106,8 @@ server.tool("search-messages", {
|
|
|
89
106
|
account: z.string().optional().describe("Account to search in (omit to search all accounts)"),
|
|
90
107
|
isRead: z.boolean().optional().describe("Filter by read status"),
|
|
91
108
|
isFlagged: z.boolean().optional().describe("Filter by flagged status"),
|
|
92
|
-
dateFrom:
|
|
93
|
-
dateTo:
|
|
109
|
+
dateFrom: DATE_FILTER_SCHEMA.describe("Start date filter (e.g., 'January 1, 2026')"),
|
|
110
|
+
dateTo: DATE_FILTER_SCHEMA.describe("End date filter (e.g., 'March 1, 2026')"),
|
|
94
111
|
limit: z.number().optional().describe("Maximum number of results (default: 50)"),
|
|
95
112
|
}, withErrorHandling(({ query, mailbox, account, limit = 50, dateFrom, dateTo }) => {
|
|
96
113
|
const messages = mailManager.searchMessages(query, mailbox, account, limit, dateFrom, dateTo);
|
|
@@ -104,7 +121,7 @@ server.tool("search-messages", {
|
|
|
104
121
|
}, "Error searching messages"));
|
|
105
122
|
// --- get-message ---
|
|
106
123
|
server.tool("get-message", {
|
|
107
|
-
id:
|
|
124
|
+
id: MESSAGE_ID_SCHEMA,
|
|
108
125
|
preferHtml: z.boolean().optional().describe("Return HTML source instead of plain text"),
|
|
109
126
|
}, withErrorHandling(({ id, preferHtml }) => {
|
|
110
127
|
const content = mailManager.getMessageContent(id);
|
|
@@ -142,13 +159,63 @@ server.tool("send-email", {
|
|
|
142
159
|
cc: z.array(z.string()).optional().describe("CC recipients"),
|
|
143
160
|
bcc: z.array(z.string()).optional().describe("BCC recipients"),
|
|
144
161
|
account: z.string().optional().describe("Account to send from"),
|
|
145
|
-
|
|
146
|
-
|
|
162
|
+
attachments: z
|
|
163
|
+
.array(z.string())
|
|
164
|
+
.max(20, "Cannot attach more than 20 files")
|
|
165
|
+
.optional()
|
|
166
|
+
.describe("Absolute file paths to attach (e.g., ['/Users/me/report.pdf'])"),
|
|
167
|
+
}, withErrorHandling(({ to, subject, body, cc, bcc, account, attachments }) => {
|
|
168
|
+
const success = mailManager.sendEmail(to, subject, body, cc, bcc, account, attachments);
|
|
147
169
|
if (!success) {
|
|
148
170
|
return errorResponse("Failed to send email. Check Mail.app configuration.");
|
|
149
171
|
}
|
|
150
|
-
|
|
172
|
+
const attachInfo = attachments?.length ? ` with ${attachments.length} attachment(s)` : "";
|
|
173
|
+
return successResponse(`Email sent to ${to.join(", ")}${attachInfo}`);
|
|
151
174
|
}, "Error sending email"));
|
|
175
|
+
// --- send-serial-email ---
|
|
176
|
+
server.tool("send-serial-email", {
|
|
177
|
+
recipients: z
|
|
178
|
+
.array(z.object({
|
|
179
|
+
email: z.string().min(1, "Recipient email is required"),
|
|
180
|
+
variables: z
|
|
181
|
+
.record(z.string())
|
|
182
|
+
.describe("Placeholder values, e.g. { Name: 'Alice', Company: 'Acme' }"),
|
|
183
|
+
}))
|
|
184
|
+
.min(1, "At least one recipient is required")
|
|
185
|
+
.max(100, "Cannot send to more than 100 recipients in a single batch")
|
|
186
|
+
.describe("List of recipients with personalization variables (max 100)"),
|
|
187
|
+
subject: z
|
|
188
|
+
.string()
|
|
189
|
+
.min(1, "Subject is required")
|
|
190
|
+
.describe("Subject line — use {{Key}} for placeholders"),
|
|
191
|
+
body: z
|
|
192
|
+
.string()
|
|
193
|
+
.min(1, "Body is required")
|
|
194
|
+
.describe("Email body — use {{Key}} for placeholders"),
|
|
195
|
+
account: z.string().optional().describe("Account to send from"),
|
|
196
|
+
delayMs: z
|
|
197
|
+
.number()
|
|
198
|
+
.min(0)
|
|
199
|
+
.max(10000)
|
|
200
|
+
.optional()
|
|
201
|
+
.describe("Delay between sends in ms (default: 500, max: 10000)"),
|
|
202
|
+
}, withErrorHandling(({ recipients, subject, body, account, delayMs }) => {
|
|
203
|
+
const results = mailManager.sendSerialEmail(recipients, subject, body, account, delayMs);
|
|
204
|
+
const successCount = results.filter((r) => r.success).length;
|
|
205
|
+
const failCount = results.length - successCount;
|
|
206
|
+
const details = results
|
|
207
|
+
.map((r) => ` - ${r.email}: ${r.success ? "sent" : `FAILED (${r.error})`}`)
|
|
208
|
+
.join("\n");
|
|
209
|
+
if (failCount === 0) {
|
|
210
|
+
return successResponse(`Successfully sent ${successCount} email(s):\n${details}`);
|
|
211
|
+
}
|
|
212
|
+
else if (successCount === 0) {
|
|
213
|
+
return errorResponse(`Failed to send all ${failCount} email(s):\n${details}`);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
return successResponse(`Sent ${successCount} of ${results.length} email(s), ${failCount} failed:\n${details}`);
|
|
217
|
+
}
|
|
218
|
+
}, "Error sending serial emails"));
|
|
152
219
|
// --- create-draft ---
|
|
153
220
|
server.tool("create-draft", {
|
|
154
221
|
to: z.array(z.string()).min(1, "At least one recipient is required"),
|
|
@@ -157,16 +224,22 @@ server.tool("create-draft", {
|
|
|
157
224
|
cc: z.array(z.string()).optional().describe("CC recipients"),
|
|
158
225
|
bcc: z.array(z.string()).optional().describe("BCC recipients"),
|
|
159
226
|
account: z.string().optional().describe("Account to create draft in"),
|
|
160
|
-
|
|
161
|
-
|
|
227
|
+
attachments: z
|
|
228
|
+
.array(z.string())
|
|
229
|
+
.max(20, "Cannot attach more than 20 files")
|
|
230
|
+
.optional()
|
|
231
|
+
.describe("Absolute file paths to attach (e.g., ['/Users/me/report.pdf'])"),
|
|
232
|
+
}, withErrorHandling(({ to, subject, body, cc, bcc, account, attachments }) => {
|
|
233
|
+
const success = mailManager.createDraft(to, subject, body, cc, bcc, account, attachments);
|
|
162
234
|
if (!success) {
|
|
163
235
|
return errorResponse("Failed to create draft. Check Mail.app configuration.");
|
|
164
236
|
}
|
|
165
|
-
|
|
237
|
+
const attachInfo = attachments?.length ? ` with ${attachments.length} attachment(s)` : "";
|
|
238
|
+
return successResponse(`Draft created for ${to.join(", ")}${attachInfo}`);
|
|
166
239
|
}, "Error creating draft"));
|
|
167
240
|
// --- reply-to-message ---
|
|
168
241
|
server.tool("reply-to-message", {
|
|
169
|
-
id:
|
|
242
|
+
id: MESSAGE_ID_SCHEMA,
|
|
170
243
|
body: z.string().min(1, "Reply body is required"),
|
|
171
244
|
replyAll: z.boolean().optional().default(false).describe("Reply to all recipients"),
|
|
172
245
|
send: z.boolean().optional().default(true).describe("Send immediately (false = save as draft)"),
|
|
@@ -179,7 +252,7 @@ server.tool("reply-to-message", {
|
|
|
179
252
|
}, "Error replying to message"));
|
|
180
253
|
// --- forward-message ---
|
|
181
254
|
server.tool("forward-message", {
|
|
182
|
-
id:
|
|
255
|
+
id: MESSAGE_ID_SCHEMA,
|
|
183
256
|
to: z.array(z.string()).min(1, "At least one recipient is required"),
|
|
184
257
|
body: z.string().optional().describe("Optional message to prepend"),
|
|
185
258
|
send: z.boolean().optional().default(true).describe("Send immediately (false = save as draft)"),
|
|
@@ -192,7 +265,7 @@ server.tool("forward-message", {
|
|
|
192
265
|
}, "Error forwarding message"));
|
|
193
266
|
// --- mark-as-read ---
|
|
194
267
|
server.tool("mark-as-read", {
|
|
195
|
-
id:
|
|
268
|
+
id: MESSAGE_ID_SCHEMA,
|
|
196
269
|
}, withErrorHandling(({ id }) => {
|
|
197
270
|
const success = mailManager.markAsRead(id);
|
|
198
271
|
if (!success) {
|
|
@@ -202,7 +275,7 @@ server.tool("mark-as-read", {
|
|
|
202
275
|
}, "Error marking message as read"));
|
|
203
276
|
// --- mark-as-unread ---
|
|
204
277
|
server.tool("mark-as-unread", {
|
|
205
|
-
id:
|
|
278
|
+
id: MESSAGE_ID_SCHEMA,
|
|
206
279
|
}, withErrorHandling(({ id }) => {
|
|
207
280
|
const success = mailManager.markAsUnread(id);
|
|
208
281
|
if (!success) {
|
|
@@ -212,7 +285,7 @@ server.tool("mark-as-unread", {
|
|
|
212
285
|
}, "Error marking message as unread"));
|
|
213
286
|
// --- flag-message ---
|
|
214
287
|
server.tool("flag-message", {
|
|
215
|
-
id:
|
|
288
|
+
id: MESSAGE_ID_SCHEMA,
|
|
216
289
|
}, withErrorHandling(({ id }) => {
|
|
217
290
|
const success = mailManager.flagMessage(id);
|
|
218
291
|
if (!success) {
|
|
@@ -222,7 +295,7 @@ server.tool("flag-message", {
|
|
|
222
295
|
}, "Error flagging message"));
|
|
223
296
|
// --- unflag-message ---
|
|
224
297
|
server.tool("unflag-message", {
|
|
225
|
-
id:
|
|
298
|
+
id: MESSAGE_ID_SCHEMA,
|
|
226
299
|
}, withErrorHandling(({ id }) => {
|
|
227
300
|
const success = mailManager.unflagMessage(id);
|
|
228
301
|
if (!success) {
|
|
@@ -232,7 +305,7 @@ server.tool("unflag-message", {
|
|
|
232
305
|
}, "Error unflagging message"));
|
|
233
306
|
// --- delete-message ---
|
|
234
307
|
server.tool("delete-message", {
|
|
235
|
-
id:
|
|
308
|
+
id: MESSAGE_ID_SCHEMA,
|
|
236
309
|
}, withErrorHandling(({ id }) => {
|
|
237
310
|
const success = mailManager.deleteMessage(id);
|
|
238
311
|
if (!success) {
|
|
@@ -242,7 +315,7 @@ server.tool("delete-message", {
|
|
|
242
315
|
}, "Error deleting message"));
|
|
243
316
|
// --- move-message ---
|
|
244
317
|
server.tool("move-message", {
|
|
245
|
-
id:
|
|
318
|
+
id: MESSAGE_ID_SCHEMA,
|
|
246
319
|
mailbox: z.string().min(1, "Destination mailbox is required"),
|
|
247
320
|
account: z.string().optional().describe("Account containing the destination mailbox"),
|
|
248
321
|
}, withErrorHandling(({ id, mailbox, account }) => {
|
|
@@ -254,7 +327,7 @@ server.tool("move-message", {
|
|
|
254
327
|
}, "Error moving message"));
|
|
255
328
|
// --- batch-delete-messages ---
|
|
256
329
|
server.tool("batch-delete-messages", {
|
|
257
|
-
ids:
|
|
330
|
+
ids: BATCH_IDS_SCHEMA,
|
|
258
331
|
}, withErrorHandling(({ ids }) => {
|
|
259
332
|
const results = mailManager.batchDeleteMessages(ids);
|
|
260
333
|
const successCount = results.filter((r) => r.success).length;
|
|
@@ -271,7 +344,7 @@ server.tool("batch-delete-messages", {
|
|
|
271
344
|
}, "Error batch deleting messages"));
|
|
272
345
|
// --- batch-move-messages ---
|
|
273
346
|
server.tool("batch-move-messages", {
|
|
274
|
-
ids:
|
|
347
|
+
ids: BATCH_IDS_SCHEMA,
|
|
275
348
|
mailbox: z.string().min(1, "Destination mailbox is required"),
|
|
276
349
|
account: z.string().optional().describe("Account containing the destination mailbox"),
|
|
277
350
|
}, withErrorHandling(({ ids, mailbox, account }) => {
|
|
@@ -290,7 +363,7 @@ server.tool("batch-move-messages", {
|
|
|
290
363
|
}, "Error batch moving messages"));
|
|
291
364
|
// --- batch-mark-as-read ---
|
|
292
365
|
server.tool("batch-mark-as-read", {
|
|
293
|
-
ids:
|
|
366
|
+
ids: BATCH_IDS_SCHEMA,
|
|
294
367
|
}, withErrorHandling(({ ids }) => {
|
|
295
368
|
const results = mailManager.batchMarkAsRead(ids);
|
|
296
369
|
const successCount = results.filter((r) => r.success).length;
|
|
@@ -307,7 +380,7 @@ server.tool("batch-mark-as-read", {
|
|
|
307
380
|
}, "Error batch marking messages as read"));
|
|
308
381
|
// --- batch-mark-as-unread ---
|
|
309
382
|
server.tool("batch-mark-as-unread", {
|
|
310
|
-
ids:
|
|
383
|
+
ids: BATCH_IDS_SCHEMA,
|
|
311
384
|
}, withErrorHandling(({ ids }) => {
|
|
312
385
|
const results = mailManager.batchMarkAsUnread(ids);
|
|
313
386
|
const successCount = results.filter((r) => r.success).length;
|
|
@@ -324,7 +397,7 @@ server.tool("batch-mark-as-unread", {
|
|
|
324
397
|
}, "Error batch marking messages as unread"));
|
|
325
398
|
// --- batch-flag-messages ---
|
|
326
399
|
server.tool("batch-flag-messages", {
|
|
327
|
-
ids:
|
|
400
|
+
ids: BATCH_IDS_SCHEMA,
|
|
328
401
|
}, withErrorHandling(({ ids }) => {
|
|
329
402
|
const results = mailManager.batchFlagMessages(ids);
|
|
330
403
|
const successCount = results.filter((r) => r.success).length;
|
|
@@ -341,7 +414,7 @@ server.tool("batch-flag-messages", {
|
|
|
341
414
|
}, "Error batch flagging messages"));
|
|
342
415
|
// --- batch-unflag-messages ---
|
|
343
416
|
server.tool("batch-unflag-messages", {
|
|
344
|
-
ids:
|
|
417
|
+
ids: BATCH_IDS_SCHEMA,
|
|
345
418
|
}, withErrorHandling(({ ids }) => {
|
|
346
419
|
const results = mailManager.batchUnflagMessages(ids);
|
|
347
420
|
const successCount = results.filter((r) => r.success).length;
|
|
@@ -358,7 +431,7 @@ server.tool("batch-unflag-messages", {
|
|
|
358
431
|
}, "Error batch unflagging messages"));
|
|
359
432
|
// --- list-attachments ---
|
|
360
433
|
server.tool("list-attachments", {
|
|
361
|
-
id:
|
|
434
|
+
id: MESSAGE_ID_SCHEMA,
|
|
362
435
|
}, withErrorHandling(({ id }) => {
|
|
363
436
|
const attachments = mailManager.listAttachments(id);
|
|
364
437
|
if (attachments.length === 0) {
|
|
@@ -374,7 +447,7 @@ server.tool("list-attachments", {
|
|
|
374
447
|
}, "Error listing attachments"));
|
|
375
448
|
// --- save-attachment ---
|
|
376
449
|
server.tool("save-attachment", {
|
|
377
|
-
id:
|
|
450
|
+
id: MESSAGE_ID_SCHEMA,
|
|
378
451
|
attachmentName: z.string().min(1, "Attachment name is required"),
|
|
379
452
|
savePath: z.string().min(1, "Save directory path is required"),
|
|
380
453
|
}, withErrorHandling(({ id, attachmentName, savePath }) => {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @module services/appleMailManager
|
|
14
14
|
*/
|
|
15
|
-
import type { Message, MessageContent, Mailbox, Account, Attachment, HealthCheckResult, MailStats, BatchOperationResult, SyncStatus, RecentlyReceivedStats, MailRule, Contact, EmailTemplate } from "../types.js";
|
|
15
|
+
import type { Message, MessageContent, Mailbox, Account, Attachment, HealthCheckResult, MailStats, BatchOperationResult, SyncStatus, RecentlyReceivedStats, MailRule, Contact, EmailTemplate, SerialEmailRecipient, SerialEmailResult } from "../types.js";
|
|
16
16
|
/**
|
|
17
17
|
* Manager class for Apple Mail operations.
|
|
18
18
|
*
|
|
@@ -124,7 +124,21 @@ export declare class AppleMailManager {
|
|
|
124
124
|
* @param account - Account to send from
|
|
125
125
|
* @returns true if sent successfully
|
|
126
126
|
*/
|
|
127
|
-
sendEmail(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string): boolean;
|
|
127
|
+
sendEmail(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string, attachments?: string[]): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Send individual personalized emails to a list of recipients (mail merge).
|
|
130
|
+
*
|
|
131
|
+
* Replaces {{placeholder}} tokens in subject and body with per-recipient values.
|
|
132
|
+
* Each recipient receives their own individual email.
|
|
133
|
+
*
|
|
134
|
+
* @param recipients - List of recipient objects with email and variable values
|
|
135
|
+
* @param subject - Email subject (may contain {{placeholders}})
|
|
136
|
+
* @param body - Email body (may contain {{placeholders}})
|
|
137
|
+
* @param account - Account to send from
|
|
138
|
+
* @param delayMs - Delay between sends in milliseconds (default: 500, max: 10000)
|
|
139
|
+
* @returns Array of per-recipient results
|
|
140
|
+
*/
|
|
141
|
+
sendSerialEmail(recipients: SerialEmailRecipient[], subject: string, body: string, account?: string, delayMs?: number): SerialEmailResult[];
|
|
128
142
|
/**
|
|
129
143
|
* Create a draft email (saved to Drafts folder, not sent).
|
|
130
144
|
*
|
|
@@ -136,7 +150,7 @@ export declare class AppleMailManager {
|
|
|
136
150
|
* @param account - Account to create draft in
|
|
137
151
|
* @returns true if draft created successfully
|
|
138
152
|
*/
|
|
139
|
-
createDraft(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string): boolean;
|
|
153
|
+
createDraft(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string, attachments?: string[]): boolean;
|
|
140
154
|
/**
|
|
141
155
|
* Reply to a message.
|
|
142
156
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @module services/appleMailManager
|
|
14
14
|
*/
|
|
15
|
+
import { spawnSync } from "child_process";
|
|
16
|
+
import { existsSync } from "fs";
|
|
17
|
+
import { isAbsolute, resolve } from "path";
|
|
18
|
+
import { homedir } from "os";
|
|
15
19
|
import { executeAppleScript } from "../utils/applescript.js";
|
|
16
20
|
// =============================================================================
|
|
17
21
|
// Text Processing Utilities
|
|
@@ -32,16 +36,54 @@ function escapeForAppleScript(text) {
|
|
|
32
36
|
return text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
33
37
|
}
|
|
34
38
|
/**
|
|
35
|
-
*
|
|
39
|
+
* Validates attachment file paths and builds AppleScript commands to attach them.
|
|
36
40
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
41
|
+
* @param attachments - Absolute file paths to attach
|
|
42
|
+
* @returns AppleScript commands to add attachments, or empty string if none
|
|
43
|
+
* @throws Error if any path is not absolute or does not exist
|
|
44
|
+
*/
|
|
45
|
+
function buildAttachmentCommands(attachments) {
|
|
46
|
+
if (!attachments || attachments.length === 0)
|
|
47
|
+
return "";
|
|
48
|
+
for (const filePath of attachments) {
|
|
49
|
+
if (!isAbsolute(filePath)) {
|
|
50
|
+
throw new Error(`Attachment path must be absolute: "${filePath}"`);
|
|
51
|
+
}
|
|
52
|
+
if (!existsSync(filePath)) {
|
|
53
|
+
throw new Error(`Attachment file not found: "${filePath}"`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let commands = "";
|
|
57
|
+
for (const filePath of attachments) {
|
|
58
|
+
const safePath = escapeForAppleScript(filePath);
|
|
59
|
+
commands += `make new attachment with properties {file name:POSIX file "${safePath}"} at after the last paragraph\n`;
|
|
60
|
+
}
|
|
61
|
+
return commands;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* AppleScript snippet that converts a date variable `d` into a
|
|
65
|
+
* locale-independent numeric string: "YYYY-M-D-H-m-s".
|
|
66
|
+
* Use: set d to date received of msg, then inline this snippet.
|
|
67
|
+
*/
|
|
68
|
+
const AS_DATE_TO_STRING = `((year of d) as string) & "-" & ((month of d as integer) as string) & "-" & ((day of d) as string) & "-" & ((hours of d) as string) & "-" & ((minutes of d) as string) & "-" & ((seconds of d) as string)`;
|
|
69
|
+
/**
|
|
70
|
+
* Parses a locale-independent date string "YYYY-M-D-H-m-s"
|
|
71
|
+
* produced by the AppleScript snippet above.
|
|
39
72
|
*
|
|
40
|
-
*
|
|
73
|
+
* Falls back to the locale-dependent `as string` format for
|
|
74
|
+
* backwards compatibility, and finally to current date.
|
|
75
|
+
*
|
|
76
|
+
* @param dateStr - Date string from AppleScript
|
|
41
77
|
* @returns Parsed Date, or current date if parsing fails
|
|
42
78
|
*/
|
|
43
|
-
function parseAppleScriptDate(
|
|
44
|
-
|
|
79
|
+
function parseAppleScriptDate(dateStr) {
|
|
80
|
+
// Try locale-independent numeric format first: "YYYY-M-D-H-m-s"
|
|
81
|
+
const numParts = dateStr.split("-").map(Number);
|
|
82
|
+
if (numParts.length === 6 && numParts.every((n) => !isNaN(n))) {
|
|
83
|
+
return new Date(numParts[0], numParts[1] - 1, numParts[2], numParts[3], numParts[4], numParts[5]);
|
|
84
|
+
}
|
|
85
|
+
// Fallback: try legacy locale-dependent format
|
|
86
|
+
const withoutPrefix = dateStr.replace(/^date\s+/, "");
|
|
45
87
|
const normalized = withoutPrefix.replace(" at ", " ");
|
|
46
88
|
const parsed = new Date(normalized);
|
|
47
89
|
return isNaN(parsed.getTime()) ? new Date() : parsed;
|
|
@@ -269,15 +311,18 @@ export class AppleMailManager {
|
|
|
269
311
|
const safeQuery = escapeForAppleScript(query);
|
|
270
312
|
searchCondition = `whose subject contains "${safeQuery}" or sender contains "${safeQuery}"`;
|
|
271
313
|
}
|
|
272
|
-
// Build date filter AppleScript
|
|
314
|
+
// Build date filter AppleScript.
|
|
315
|
+
// Note: dateFrom/dateTo are already validated by DATE_FILTER_SCHEMA (alphanumeric + safe
|
|
316
|
+
// punctuation only), so escapeForAppleScript() below is belt-and-suspenders — it won't
|
|
317
|
+
// alter valid date strings but guards against future schema changes.
|
|
273
318
|
let dateFilter = "";
|
|
274
319
|
if (dateFrom || dateTo) {
|
|
275
320
|
const dateChecks = [];
|
|
276
321
|
if (dateFrom) {
|
|
277
|
-
dateChecks.push(`date received of msg >= date "${dateFrom}"`);
|
|
322
|
+
dateChecks.push(`date received of msg >= date "${escapeForAppleScript(dateFrom)}"`);
|
|
278
323
|
}
|
|
279
324
|
if (dateTo) {
|
|
280
|
-
dateChecks.push(`date received of msg <= date "${dateTo}"`);
|
|
325
|
+
dateChecks.push(`date received of msg <= date "${escapeForAppleScript(dateTo)}"`);
|
|
281
326
|
}
|
|
282
327
|
dateFilter = dateChecks.join(" and ");
|
|
283
328
|
}
|
|
@@ -293,7 +338,8 @@ export class AppleMailManager {
|
|
|
293
338
|
set msgId to id of msg as string
|
|
294
339
|
set msgSubject to subject of msg
|
|
295
340
|
set msgSender to sender of msg
|
|
296
|
-
set
|
|
341
|
+
set d to date received of msg
|
|
342
|
+
set msgDateStr to ${AS_DATE_TO_STRING}
|
|
297
343
|
set msgRead to read status of msg as string
|
|
298
344
|
set msgFlagged to flagged status of msg as string
|
|
299
345
|
if msgCount > 0 then set outputText to outputText & "|||ITEM|||"
|
|
@@ -326,12 +372,13 @@ export class AppleMailManager {
|
|
|
326
372
|
repeat with acct in accounts
|
|
327
373
|
repeat with mb in mailboxes of acct
|
|
328
374
|
try
|
|
329
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
375
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
330
376
|
if (count of matchingMsgs) > 0 then
|
|
331
377
|
set msg to item 1 of matchingMsgs
|
|
332
378
|
set msgSubject to subject of msg
|
|
333
379
|
set msgSender to sender of msg
|
|
334
|
-
set
|
|
380
|
+
set d to date received of msg
|
|
381
|
+
set msgDate to ${AS_DATE_TO_STRING}
|
|
335
382
|
set msgRead to read status of msg as string
|
|
336
383
|
set msgFlagged to flagged status of msg as string
|
|
337
384
|
set msgJunk to junk mail status of msg as string
|
|
@@ -380,7 +427,7 @@ export class AppleMailManager {
|
|
|
380
427
|
repeat with acct in accounts
|
|
381
428
|
repeat with mb in mailboxes of acct
|
|
382
429
|
try
|
|
383
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
430
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
384
431
|
if (count of matchingMsgs) > 0 then
|
|
385
432
|
set msg to item 1 of matchingMsgs
|
|
386
433
|
set msgSubject to subject of msg
|
|
@@ -445,7 +492,8 @@ export class AppleMailManager {
|
|
|
445
492
|
set msgId to id of msg as string
|
|
446
493
|
set msgSubject to subject of msg
|
|
447
494
|
set msgSender to sender of msg
|
|
448
|
-
set
|
|
495
|
+
set d to date received of msg
|
|
496
|
+
set msgDate to ${AS_DATE_TO_STRING}
|
|
449
497
|
set msgRead to read status of msg as string
|
|
450
498
|
set msgFlagged to flagged status of msg as string
|
|
451
499
|
if msgCount > 0 then set outputText to outputText & "|||ITEM|||"
|
|
@@ -504,7 +552,7 @@ export class AppleMailManager {
|
|
|
504
552
|
* @param account - Account to send from
|
|
505
553
|
* @returns true if sent successfully
|
|
506
554
|
*/
|
|
507
|
-
sendEmail(to, subject, body, cc, bcc, account) {
|
|
555
|
+
sendEmail(to, subject, body, cc, bcc, account, attachments) {
|
|
508
556
|
const safeSubject = escapeForAppleScript(subject);
|
|
509
557
|
const safeBody = escapeForAppleScript(body);
|
|
510
558
|
// Build recipient additions
|
|
@@ -522,6 +570,7 @@ export class AppleMailManager {
|
|
|
522
570
|
recipientCommands += `make new bcc recipient at end of bcc recipients with properties {address:"${escapeForAppleScript(addr)}"}\n`;
|
|
523
571
|
}
|
|
524
572
|
}
|
|
573
|
+
const attachmentCommands = buildAttachmentCommands(attachments);
|
|
525
574
|
let sendCommand;
|
|
526
575
|
if (account) {
|
|
527
576
|
const safeAccount = escapeForAppleScript(account);
|
|
@@ -530,6 +579,7 @@ export class AppleMailManager {
|
|
|
530
579
|
tell newMessage
|
|
531
580
|
${recipientCommands}
|
|
532
581
|
set sender to "${safeAccount}"
|
|
582
|
+
${attachmentCommands}
|
|
533
583
|
end tell
|
|
534
584
|
send newMessage
|
|
535
585
|
return "sent"
|
|
@@ -540,19 +590,69 @@ export class AppleMailManager {
|
|
|
540
590
|
set newMessage to make new outgoing message with properties {subject:"${safeSubject}", content:"${safeBody}", visible:true}
|
|
541
591
|
tell newMessage
|
|
542
592
|
${recipientCommands}
|
|
593
|
+
${attachmentCommands}
|
|
543
594
|
end tell
|
|
544
595
|
send newMessage
|
|
545
596
|
return "sent"
|
|
546
597
|
`;
|
|
547
598
|
}
|
|
548
599
|
const script = buildAppLevelScript(sendCommand);
|
|
549
|
-
const result = executeAppleScript(script);
|
|
600
|
+
const result = executeAppleScript(script, { timeoutMs: 60000, maxRetries: 2 });
|
|
550
601
|
if (!result.success) {
|
|
551
602
|
console.error(`Failed to send email: ${result.error}`);
|
|
552
603
|
return false;
|
|
553
604
|
}
|
|
554
605
|
return result.output.includes("sent");
|
|
555
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Send individual personalized emails to a list of recipients (mail merge).
|
|
609
|
+
*
|
|
610
|
+
* Replaces {{placeholder}} tokens in subject and body with per-recipient values.
|
|
611
|
+
* Each recipient receives their own individual email.
|
|
612
|
+
*
|
|
613
|
+
* @param recipients - List of recipient objects with email and variable values
|
|
614
|
+
* @param subject - Email subject (may contain {{placeholders}})
|
|
615
|
+
* @param body - Email body (may contain {{placeholders}})
|
|
616
|
+
* @param account - Account to send from
|
|
617
|
+
* @param delayMs - Delay between sends in milliseconds (default: 500, max: 10000)
|
|
618
|
+
* @returns Array of per-recipient results
|
|
619
|
+
*/
|
|
620
|
+
sendSerialEmail(recipients, subject, body, account, delayMs = 500) {
|
|
621
|
+
const effectiveDelay = Math.min(Math.max(delayMs, 0), 10000);
|
|
622
|
+
const results = [];
|
|
623
|
+
for (let i = 0; i < recipients.length; i++) {
|
|
624
|
+
const recipient = recipients[i];
|
|
625
|
+
try {
|
|
626
|
+
// Replace all {{Key}} placeholders with recipient's values
|
|
627
|
+
let personalizedSubject = subject;
|
|
628
|
+
let personalizedBody = body;
|
|
629
|
+
for (const [key, value] of Object.entries(recipient.variables)) {
|
|
630
|
+
const safeKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
631
|
+
const placeholder = new RegExp(`\\{\\{${safeKey}\\}\\}`, "g");
|
|
632
|
+
personalizedSubject = personalizedSubject.replace(placeholder, value);
|
|
633
|
+
personalizedBody = personalizedBody.replace(placeholder, value);
|
|
634
|
+
}
|
|
635
|
+
const success = this.sendEmail([recipient.email], personalizedSubject, personalizedBody, undefined, undefined, account);
|
|
636
|
+
results.push({
|
|
637
|
+
email: recipient.email,
|
|
638
|
+
success,
|
|
639
|
+
error: success ? undefined : "Failed to send email",
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
results.push({
|
|
644
|
+
email: recipient.email,
|
|
645
|
+
success: false,
|
|
646
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
// Brief delay between sends to avoid overwhelming Mail.app
|
|
650
|
+
if (effectiveDelay > 0 && i < recipients.length - 1) {
|
|
651
|
+
spawnSync("sleep", [(effectiveDelay / 1000).toString()], { stdio: "ignore" });
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return results;
|
|
655
|
+
}
|
|
556
656
|
/**
|
|
557
657
|
* Create a draft email (saved to Drafts folder, not sent).
|
|
558
658
|
*
|
|
@@ -564,7 +664,7 @@ export class AppleMailManager {
|
|
|
564
664
|
* @param account - Account to create draft in
|
|
565
665
|
* @returns true if draft created successfully
|
|
566
666
|
*/
|
|
567
|
-
createDraft(to, subject, body, cc, bcc, account) {
|
|
667
|
+
createDraft(to, subject, body, cc, bcc, account, attachments) {
|
|
568
668
|
const safeSubject = escapeForAppleScript(subject);
|
|
569
669
|
const safeBody = escapeForAppleScript(body);
|
|
570
670
|
// Build recipient additions
|
|
@@ -582,6 +682,7 @@ export class AppleMailManager {
|
|
|
582
682
|
recipientCommands += `make new bcc recipient at end of bcc recipients with properties {address:"${escapeForAppleScript(addr)}"}\n`;
|
|
583
683
|
}
|
|
584
684
|
}
|
|
685
|
+
const attachmentCommands = buildAttachmentCommands(attachments);
|
|
585
686
|
let draftCommand;
|
|
586
687
|
if (account) {
|
|
587
688
|
const safeAccount = escapeForAppleScript(account);
|
|
@@ -590,6 +691,7 @@ export class AppleMailManager {
|
|
|
590
691
|
tell newMessage
|
|
591
692
|
${recipientCommands}
|
|
592
693
|
set sender to "${safeAccount}"
|
|
694
|
+
${attachmentCommands}
|
|
593
695
|
end tell
|
|
594
696
|
return "draft created"
|
|
595
697
|
`;
|
|
@@ -599,12 +701,13 @@ export class AppleMailManager {
|
|
|
599
701
|
set newMessage to make new outgoing message with properties {subject:"${safeSubject}", content:"${safeBody}", visible:false}
|
|
600
702
|
tell newMessage
|
|
601
703
|
${recipientCommands}
|
|
704
|
+
${attachmentCommands}
|
|
602
705
|
end tell
|
|
603
706
|
return "draft created"
|
|
604
707
|
`;
|
|
605
708
|
}
|
|
606
709
|
const script = buildAppLevelScript(draftCommand);
|
|
607
|
-
const result = executeAppleScript(script);
|
|
710
|
+
const result = executeAppleScript(script, { timeoutMs: 60000, maxRetries: 2 });
|
|
608
711
|
if (!result.success) {
|
|
609
712
|
console.error(`Failed to create draft: ${result.error}`);
|
|
610
713
|
return false;
|
|
@@ -629,7 +732,7 @@ export class AppleMailManager {
|
|
|
629
732
|
repeat with acct in accounts
|
|
630
733
|
repeat with mb in mailboxes of acct
|
|
631
734
|
try
|
|
632
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
735
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
633
736
|
if (count of matchingMsgs) > 0 then
|
|
634
737
|
set msg to item 1 of matchingMsgs
|
|
635
738
|
set theReply to reply msg with opening window${replyAllClause}
|
|
@@ -674,7 +777,7 @@ export class AppleMailManager {
|
|
|
674
777
|
repeat with acct in accounts
|
|
675
778
|
repeat with mb in mailboxes of acct
|
|
676
779
|
try
|
|
677
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
780
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
678
781
|
if (count of matchingMsgs) > 0 then
|
|
679
782
|
set msg to item 1 of matchingMsgs
|
|
680
783
|
set theForward to forward msg with opening window
|
|
@@ -707,7 +810,7 @@ export class AppleMailManager {
|
|
|
707
810
|
repeat with acct in accounts
|
|
708
811
|
repeat with mb in mailboxes of acct
|
|
709
812
|
try
|
|
710
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
813
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
711
814
|
if (count of matchingMsgs) > 0 then
|
|
712
815
|
set msg to item 1 of matchingMsgs
|
|
713
816
|
${operation}
|
|
@@ -795,7 +898,7 @@ export class AppleMailManager {
|
|
|
795
898
|
repeat with acct in accounts
|
|
796
899
|
repeat with mb in mailboxes of acct
|
|
797
900
|
try
|
|
798
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
901
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
799
902
|
if (count of matchingMsgs) > 0 then
|
|
800
903
|
set msg to item 1 of matchingMsgs
|
|
801
904
|
set destMailbox to mailbox "${safeMailbox}" of account "${safeAccount}"
|
|
@@ -915,7 +1018,7 @@ export class AppleMailManager {
|
|
|
915
1018
|
repeat with acct in accounts
|
|
916
1019
|
repeat with mb in mailboxes of acct
|
|
917
1020
|
try
|
|
918
|
-
set matchingMsgs to (messages of mb whose id is ${id})
|
|
1021
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
919
1022
|
if (count of matchingMsgs) > 0 then
|
|
920
1023
|
set msg to item 1 of matchingMsgs
|
|
921
1024
|
set outputText to ""
|
|
@@ -961,14 +1064,30 @@ export class AppleMailManager {
|
|
|
961
1064
|
* Save an attachment from a message to disk.
|
|
962
1065
|
*/
|
|
963
1066
|
saveAttachment(id, attachmentName, savePath) {
|
|
1067
|
+
// Validate attachment name: block path separators, traversal, null bytes, and backslashes
|
|
1068
|
+
if (/[/\\\0]/.test(attachmentName) || attachmentName.includes("..")) {
|
|
1069
|
+
console.error(`Invalid attachment name: "${attachmentName}"`);
|
|
1070
|
+
return false;
|
|
1071
|
+
}
|
|
1072
|
+
// Resolve the save path to prevent symlink / ".." traversal bypass
|
|
1073
|
+
const resolvedPath = resolve(savePath);
|
|
1074
|
+
const allowedPrefixes = [homedir(), "/tmp", "/private/tmp", "/Volumes"];
|
|
1075
|
+
const isAllowed = allowedPrefixes.some((prefix) => resolvedPath.startsWith(prefix));
|
|
1076
|
+
if (!isAllowed) {
|
|
1077
|
+
console.error(`Save path "${savePath}" is outside allowed directories`);
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
964
1080
|
const safeName = escapeForAppleScript(attachmentName);
|
|
965
|
-
const safePath = escapeForAppleScript(
|
|
1081
|
+
const safePath = escapeForAppleScript(resolvedPath);
|
|
1082
|
+
// Use Number(id) as defense-in-depth — the Zod schema already enforces numeric IDs,
|
|
1083
|
+
// but this ensures raw interpolation into AppleScript is safe even if validation changes.
|
|
1084
|
+
const numericId = Number(id);
|
|
966
1085
|
const script = buildAppLevelScript(`
|
|
967
1086
|
try
|
|
968
1087
|
repeat with acct in accounts
|
|
969
1088
|
repeat with mb in mailboxes of acct
|
|
970
1089
|
try
|
|
971
|
-
set matchingMsgs to (messages of mb whose id is ${
|
|
1090
|
+
set matchingMsgs to (messages of mb whose id is ${numericId})
|
|
972
1091
|
if (count of matchingMsgs) > 0 then
|
|
973
1092
|
set msg to item 1 of matchingMsgs
|
|
974
1093
|
repeat with att in mail attachments of msg
|
package/build/types.d.ts
CHANGED
|
@@ -207,6 +207,26 @@ export interface MoveMessageParams {
|
|
|
207
207
|
/** Account containing the destination mailbox */
|
|
208
208
|
account?: string;
|
|
209
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* A single recipient in a serial email (mail merge) operation.
|
|
212
|
+
*/
|
|
213
|
+
export interface SerialEmailRecipient {
|
|
214
|
+
/** Recipient email address */
|
|
215
|
+
email: string;
|
|
216
|
+
/** Variable values for placeholder replacement (e.g., { Name: "Alice", Company: "Acme" }) */
|
|
217
|
+
variables: Record<string, string>;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Result of sending a serial email to a single recipient.
|
|
221
|
+
*/
|
|
222
|
+
export interface SerialEmailResult {
|
|
223
|
+
/** Recipient email address */
|
|
224
|
+
email: string;
|
|
225
|
+
/** Whether the email was sent successfully */
|
|
226
|
+
success: boolean;
|
|
227
|
+
/** Error message if sending failed */
|
|
228
|
+
error?: string;
|
|
229
|
+
}
|
|
210
230
|
/**
|
|
211
231
|
* Individual check result in a health check.
|
|
212
232
|
*/
|
package/build/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IAEX,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IAEf,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,4BAA4B;IAC5B,UAAU,EAAE,MAAM,EAAE,CAAC;IAErB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB,oCAAoC;IACpC,YAAY,EAAE,IAAI,CAAC;IAEnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,IAAI,CAAC;IAEhB,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC;IAEhB,qCAAqC;IACrC,SAAS,EAAE,OAAO,CAAC;IAEnB,4CAA4C;IAC5C,MAAM,EAAE,OAAO,CAAC;IAEhB,2CAA2C;IAC3C,SAAS,EAAE,OAAO,CAAC;IAEnB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAEhB,0CAA0C;IAC1C,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IAEX,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAEhB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAElB,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAEhB,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC;IAEpB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IAEd,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAC;IAEX,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IAEb,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IAEjB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAMD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IAEjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IAEf,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,+BAA+B;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,IAAI,CAAC;IAEhB,gCAAgC;IAChC,MAAM,CAAC,EAAE,IAAI,CAAC;IAEd,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,EAAE,CAAC;IAEb,oBAAoB;IACpB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAEd,qBAAqB;IACrB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IAEf,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAEhB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IAEb,yCAAyC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qCAAqC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IAEX,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IAEd,6FAA6F;IAC7F,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IAEd,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IAEjB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IAEb,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAC;IAEhB,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAC;IAEjB,+BAA+B;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAMD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IAErB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IAEtB,4BAA4B;IAC5B,cAAc,EAAE,MAAM,CAAC;IAEvB,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IAErB,6BAA6B;IAC7B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAEhB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IAEf,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IAEtB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IAEpB,6BAA6B;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAC;IAEzB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAMD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IAEX,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IAEjB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,sBAAsB;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB,oBAAoB;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IAEX,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IAEb,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAEhB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IAEb,yBAAyB;IACzB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAEd,4BAA4B;IAC5B,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;CACf;AAMD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,YAAY,EAAE,OAAO,CAAC;IAEtB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IAEtB,iDAAiD;IACjD,cAAc,EAAE,OAAO,CAAC;IAExB,yCAAyC;IACzC,sBAAsB,EAAE,MAAM,CAAC;IAE/B,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-mail-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
"start": "node build/index.js",
|
|
19
19
|
"dev": "tsc --watch",
|
|
20
20
|
"test": "vitest run",
|
|
21
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
22
|
+
"test:all": "vitest run && vitest run --config vitest.integration.config.ts",
|
|
21
23
|
"test:watch": "vitest",
|
|
22
24
|
"test:coverage": "vitest run --coverage",
|
|
23
25
|
"lint": "eslint src",
|