apple-mail-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js ADDED
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Apple Mail MCP Server
4
+ *
5
+ * A Model Context Protocol (MCP) server that provides AI assistants
6
+ * with the ability to interact with Apple Mail on macOS.
7
+ *
8
+ * This server exposes tools for:
9
+ * - Reading and searching emails
10
+ * - Sending emails
11
+ * - Managing mailboxes
12
+ * - Managing multiple accounts (iCloud, Gmail, Exchange, etc.)
13
+ *
14
+ * Architecture:
15
+ * - Tool definitions are declarative (schema + handler)
16
+ * - The AppleMailManager class handles all AppleScript operations
17
+ * - Error handling is consistent across all tools
18
+ *
19
+ * @module apple-mail-mcp
20
+ * @see https://modelcontextprotocol.io
21
+ */
22
+ import { createRequire } from "module";
23
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
24
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
+ import { z } from "zod";
26
+ import { AppleMailManager } from "./services/appleMailManager.js";
27
+ // Read version from package.json to keep it in sync
28
+ const require = createRequire(import.meta.url);
29
+ const { version } = require("../package.json");
30
+ // =============================================================================
31
+ // Server Initialization
32
+ // =============================================================================
33
+ /**
34
+ * MCP server instance configured for Apple Mail operations.
35
+ */
36
+ const server = new McpServer({
37
+ name: "apple-mail",
38
+ version,
39
+ description: "MCP server for managing Apple Mail - read, search, send, and organize emails",
40
+ });
41
+ /**
42
+ * Singleton instance of the Apple Mail manager.
43
+ * Handles all AppleScript execution and mail operations.
44
+ */
45
+ const mailManager = new AppleMailManager();
46
+ // =============================================================================
47
+ // Response Helpers
48
+ // =============================================================================
49
+ /**
50
+ * Creates a successful MCP tool response.
51
+ */
52
+ function successResponse(message) {
53
+ return {
54
+ content: [{ type: "text", text: message }],
55
+ };
56
+ }
57
+ /**
58
+ * Creates an error MCP tool response.
59
+ */
60
+ function errorResponse(message) {
61
+ return {
62
+ content: [{ type: "text", text: message }],
63
+ isError: true,
64
+ };
65
+ }
66
+ /**
67
+ * Wraps a tool handler with consistent error handling.
68
+ */
69
+ function withErrorHandling(handler, errorPrefix) {
70
+ return async (params) => {
71
+ try {
72
+ return handler(params);
73
+ }
74
+ catch (error) {
75
+ const message = error instanceof Error ? error.message : "Unknown error";
76
+ return errorResponse(`${errorPrefix}: ${message}`);
77
+ }
78
+ };
79
+ }
80
+ // =============================================================================
81
+ // Message Tools
82
+ // =============================================================================
83
+ // --- search-messages ---
84
+ server.tool("search-messages", {
85
+ query: z.string().optional().describe("Text to search for in subject, sender, or content"),
86
+ from: z.string().optional().describe("Filter by sender email address"),
87
+ subject: z.string().optional().describe("Filter by subject line"),
88
+ mailbox: z.string().optional().describe("Mailbox to search in (e.g., 'INBOX')"),
89
+ account: z.string().optional().describe("Account to search in"),
90
+ isRead: z.boolean().optional().describe("Filter by read status"),
91
+ isFlagged: z.boolean().optional().describe("Filter by flagged status"),
92
+ limit: z.number().optional().describe("Maximum number of results (default: 50)"),
93
+ }, withErrorHandling(({ query, mailbox, account, limit = 50 }) => {
94
+ const messages = mailManager.searchMessages(query, mailbox, account, limit);
95
+ if (messages.length === 0) {
96
+ return successResponse("No messages found matching criteria");
97
+ }
98
+ const messageList = messages
99
+ .map((m) => ` - ${m.subject} (from: ${m.sender}) [${m.isRead ? "read" : "unread"}]`)
100
+ .join("\n");
101
+ return successResponse(`Found ${messages.length} message(s):\n${messageList}`);
102
+ }, "Error searching messages"));
103
+ // --- get-message ---
104
+ server.tool("get-message", {
105
+ id: z.string().min(1, "Message ID is required"),
106
+ }, withErrorHandling(({ id }) => {
107
+ const content = mailManager.getMessageContent(id);
108
+ if (!content) {
109
+ return errorResponse(`Message with ID "${id}" not found`);
110
+ }
111
+ return successResponse(`Subject: ${content.subject}\n\n${content.plainText}`);
112
+ }, "Error retrieving message"));
113
+ // --- list-messages ---
114
+ server.tool("list-messages", {
115
+ mailbox: z.string().optional().describe("Mailbox to list messages from (default: INBOX)"),
116
+ account: z.string().optional().describe("Account to list messages from"),
117
+ limit: z.number().optional().describe("Maximum number of messages (default: 50)"),
118
+ unreadOnly: z.boolean().optional().describe("Only show unread messages"),
119
+ }, withErrorHandling(({ mailbox, account, limit = 50 }) => {
120
+ const messages = mailManager.listMessages(mailbox, account, limit);
121
+ if (messages.length === 0) {
122
+ return successResponse("No messages found");
123
+ }
124
+ const messageList = messages.map((m) => ` - ${m.subject} (from: ${m.sender})`).join("\n");
125
+ return successResponse(`Found ${messages.length} message(s):\n${messageList}`);
126
+ }, "Error listing messages"));
127
+ // --- send-email ---
128
+ server.tool("send-email", {
129
+ to: z.array(z.string()).min(1, "At least one recipient is required"),
130
+ subject: z.string().min(1, "Subject is required"),
131
+ body: z.string().min(1, "Body is required"),
132
+ cc: z.array(z.string()).optional().describe("CC recipients"),
133
+ bcc: z.array(z.string()).optional().describe("BCC recipients"),
134
+ account: z.string().optional().describe("Account to send from"),
135
+ }, withErrorHandling(({ to, subject, body, cc, bcc, account }) => {
136
+ const success = mailManager.sendEmail(to, subject, body, cc, bcc, account);
137
+ if (!success) {
138
+ return errorResponse("Failed to send email. Check Mail.app configuration.");
139
+ }
140
+ return successResponse(`Email sent to ${to.join(", ")}`);
141
+ }, "Error sending email"));
142
+ // --- create-draft ---
143
+ server.tool("create-draft", {
144
+ to: z.array(z.string()).min(1, "At least one recipient is required"),
145
+ subject: z.string().min(1, "Subject is required"),
146
+ body: z.string().min(1, "Body is required"),
147
+ cc: z.array(z.string()).optional().describe("CC recipients"),
148
+ bcc: z.array(z.string()).optional().describe("BCC recipients"),
149
+ account: z.string().optional().describe("Account to create draft in"),
150
+ }, withErrorHandling(({ to, subject, body, cc, bcc, account }) => {
151
+ const success = mailManager.createDraft(to, subject, body, cc, bcc, account);
152
+ if (!success) {
153
+ return errorResponse("Failed to create draft. Check Mail.app configuration.");
154
+ }
155
+ return successResponse(`Draft created for ${to.join(", ")}`);
156
+ }, "Error creating draft"));
157
+ // --- reply-to-message ---
158
+ server.tool("reply-to-message", {
159
+ id: z.string().min(1, "Message ID is required"),
160
+ body: z.string().min(1, "Reply body is required"),
161
+ replyAll: z.boolean().optional().default(false).describe("Reply to all recipients"),
162
+ send: z.boolean().optional().default(true).describe("Send immediately (false = save as draft)"),
163
+ }, withErrorHandling(({ id, body, replyAll, send }) => {
164
+ const success = mailManager.replyToMessage(id, body, replyAll, send);
165
+ if (!success) {
166
+ return errorResponse(`Failed to reply to message "${id}"`);
167
+ }
168
+ return successResponse(send ? "Reply sent" : "Reply saved as draft");
169
+ }, "Error replying to message"));
170
+ // --- forward-message ---
171
+ server.tool("forward-message", {
172
+ id: z.string().min(1, "Message ID is required"),
173
+ to: z.array(z.string()).min(1, "At least one recipient is required"),
174
+ body: z.string().optional().describe("Optional message to prepend"),
175
+ send: z.boolean().optional().default(true).describe("Send immediately (false = save as draft)"),
176
+ }, withErrorHandling(({ id, to, body, send }) => {
177
+ const success = mailManager.forwardMessage(id, to, body, send);
178
+ if (!success) {
179
+ return errorResponse(`Failed to forward message "${id}"`);
180
+ }
181
+ return successResponse(send ? `Message forwarded to ${to.join(", ")}` : "Forward saved as draft");
182
+ }, "Error forwarding message"));
183
+ // --- mark-as-read ---
184
+ server.tool("mark-as-read", {
185
+ id: z.string().min(1, "Message ID is required"),
186
+ }, withErrorHandling(({ id }) => {
187
+ const success = mailManager.markAsRead(id);
188
+ if (!success) {
189
+ return errorResponse(`Failed to mark message "${id}" as read`);
190
+ }
191
+ return successResponse("Message marked as read");
192
+ }, "Error marking message as read"));
193
+ // --- mark-as-unread ---
194
+ server.tool("mark-as-unread", {
195
+ id: z.string().min(1, "Message ID is required"),
196
+ }, withErrorHandling(({ id }) => {
197
+ const success = mailManager.markAsUnread(id);
198
+ if (!success) {
199
+ return errorResponse(`Failed to mark message "${id}" as unread`);
200
+ }
201
+ return successResponse("Message marked as unread");
202
+ }, "Error marking message as unread"));
203
+ // --- flag-message ---
204
+ server.tool("flag-message", {
205
+ id: z.string().min(1, "Message ID is required"),
206
+ }, withErrorHandling(({ id }) => {
207
+ const success = mailManager.flagMessage(id);
208
+ if (!success) {
209
+ return errorResponse(`Failed to flag message "${id}"`);
210
+ }
211
+ return successResponse("Message flagged");
212
+ }, "Error flagging message"));
213
+ // --- delete-message ---
214
+ server.tool("delete-message", {
215
+ id: z.string().min(1, "Message ID is required"),
216
+ }, withErrorHandling(({ id }) => {
217
+ const success = mailManager.deleteMessage(id);
218
+ if (!success) {
219
+ return errorResponse(`Failed to delete message "${id}"`);
220
+ }
221
+ return successResponse("Message deleted");
222
+ }, "Error deleting message"));
223
+ // --- move-message ---
224
+ server.tool("move-message", {
225
+ id: z.string().min(1, "Message ID is required"),
226
+ mailbox: z.string().min(1, "Destination mailbox is required"),
227
+ account: z.string().optional().describe("Account containing the destination mailbox"),
228
+ }, withErrorHandling(({ id, mailbox, account }) => {
229
+ const success = mailManager.moveMessage(id, mailbox, account);
230
+ if (!success) {
231
+ return errorResponse(`Failed to move message to "${mailbox}"`);
232
+ }
233
+ return successResponse(`Message moved to "${mailbox}"`);
234
+ }, "Error moving message"));
235
+ // --- batch-delete-messages ---
236
+ server.tool("batch-delete-messages", {
237
+ ids: z.array(z.string()).min(1, "At least one message ID is required"),
238
+ }, withErrorHandling(({ ids }) => {
239
+ const results = mailManager.batchDeleteMessages(ids);
240
+ const successCount = results.filter((r) => r.success).length;
241
+ const failCount = results.length - successCount;
242
+ if (failCount === 0) {
243
+ return successResponse(`Successfully deleted ${successCount} message(s)`);
244
+ }
245
+ else if (successCount === 0) {
246
+ return errorResponse(`Failed to delete all ${failCount} message(s)`);
247
+ }
248
+ else {
249
+ return successResponse(`Deleted ${successCount} message(s), ${failCount} failed`);
250
+ }
251
+ }, "Error batch deleting messages"));
252
+ // --- batch-move-messages ---
253
+ server.tool("batch-move-messages", {
254
+ ids: z.array(z.string()).min(1, "At least one message ID is required"),
255
+ mailbox: z.string().min(1, "Destination mailbox is required"),
256
+ account: z.string().optional().describe("Account containing the destination mailbox"),
257
+ }, withErrorHandling(({ ids, mailbox, account }) => {
258
+ const results = mailManager.batchMoveMessages(ids, mailbox, account);
259
+ const successCount = results.filter((r) => r.success).length;
260
+ const failCount = results.length - successCount;
261
+ if (failCount === 0) {
262
+ return successResponse(`Successfully moved ${successCount} message(s) to "${mailbox}"`);
263
+ }
264
+ else if (successCount === 0) {
265
+ return errorResponse(`Failed to move all ${failCount} message(s)`);
266
+ }
267
+ else {
268
+ return successResponse(`Moved ${successCount} message(s) to "${mailbox}", ${failCount} failed`);
269
+ }
270
+ }, "Error batch moving messages"));
271
+ // --- batch-mark-as-read ---
272
+ server.tool("batch-mark-as-read", {
273
+ ids: z.array(z.string()).min(1, "At least one message ID is required"),
274
+ }, withErrorHandling(({ ids }) => {
275
+ const results = mailManager.batchMarkAsRead(ids);
276
+ const successCount = results.filter((r) => r.success).length;
277
+ const failCount = results.length - successCount;
278
+ if (failCount === 0) {
279
+ return successResponse(`Successfully marked ${successCount} message(s) as read`);
280
+ }
281
+ else if (successCount === 0) {
282
+ return errorResponse(`Failed to mark all ${failCount} message(s) as read`);
283
+ }
284
+ else {
285
+ return successResponse(`Marked ${successCount} message(s) as read, ${failCount} failed`);
286
+ }
287
+ }, "Error batch marking messages as read"));
288
+ // --- list-attachments ---
289
+ server.tool("list-attachments", {
290
+ id: z.string().min(1, "Message ID is required"),
291
+ }, withErrorHandling(({ id }) => {
292
+ const attachments = mailManager.listAttachments(id);
293
+ if (attachments.length === 0) {
294
+ return successResponse("No attachments found");
295
+ }
296
+ const attachmentList = attachments
297
+ .map((a) => {
298
+ const sizeKb = Math.round(a.size / 1024);
299
+ return ` - ${a.name} (${a.mimeType}, ${sizeKb} KB)`;
300
+ })
301
+ .join("\n");
302
+ return successResponse(`Found ${attachments.length} attachment(s):\n${attachmentList}`);
303
+ }, "Error listing attachments"));
304
+ // =============================================================================
305
+ // Mailbox Tools
306
+ // =============================================================================
307
+ // --- list-mailboxes ---
308
+ server.tool("list-mailboxes", {
309
+ account: z.string().optional().describe("Account to list mailboxes from"),
310
+ }, withErrorHandling(({ account }) => {
311
+ const mailboxes = mailManager.listMailboxes(account);
312
+ if (mailboxes.length === 0) {
313
+ return successResponse("No mailboxes found");
314
+ }
315
+ const mailboxList = mailboxes.map((m) => ` - ${m.name} (${m.unreadCount} unread)`).join("\n");
316
+ return successResponse(`Found ${mailboxes.length} mailbox(es):\n${mailboxList}`);
317
+ }, "Error listing mailboxes"));
318
+ // --- get-unread-count ---
319
+ server.tool("get-unread-count", {
320
+ mailbox: z.string().optional().describe("Mailbox to check (default: all)"),
321
+ account: z.string().optional().describe("Account to check"),
322
+ }, withErrorHandling(({ mailbox, account }) => {
323
+ const count = mailManager.getUnreadCount(mailbox, account);
324
+ const location = mailbox ? ` in "${mailbox}"` : "";
325
+ return successResponse(`${count} unread message(s)${location}`);
326
+ }, "Error getting unread count"));
327
+ // =============================================================================
328
+ // Account Tools
329
+ // =============================================================================
330
+ // --- list-accounts ---
331
+ server.tool("list-accounts", {}, withErrorHandling(() => {
332
+ const accounts = mailManager.listAccounts();
333
+ if (accounts.length === 0) {
334
+ return successResponse("No Mail accounts found");
335
+ }
336
+ const accountList = accounts.map((a) => ` - ${a.name}`).join("\n");
337
+ return successResponse(`Found ${accounts.length} account(s):\n${accountList}`);
338
+ }, "Error listing accounts"));
339
+ // =============================================================================
340
+ // Diagnostics Tools
341
+ // =============================================================================
342
+ // --- health-check ---
343
+ server.tool("health-check", {}, withErrorHandling(() => {
344
+ const result = mailManager.healthCheck();
345
+ const statusIcon = result.healthy ? "✓" : "✗";
346
+ const statusText = result.healthy ? "All checks passed" : "Issues detected";
347
+ const checkLines = result.checks
348
+ .map((c) => {
349
+ const icon = c.passed ? "✓" : "✗";
350
+ return ` ${icon} ${c.name}: ${c.message}`;
351
+ })
352
+ .join("\n");
353
+ return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}`);
354
+ }, "Error running health check"));
355
+ // --- get-mail-stats ---
356
+ server.tool("get-mail-stats", {}, withErrorHandling(() => {
357
+ const stats = mailManager.getMailStats();
358
+ const lines = [];
359
+ lines.push(`📊 Mail Statistics`);
360
+ lines.push(`══════════════════`);
361
+ lines.push(`Total messages: ${stats.totalMessages}`);
362
+ lines.push(`Unread messages: ${stats.totalUnread}`);
363
+ lines.push(``);
364
+ if (stats.recentlyReceived) {
365
+ lines.push(`📥 Recently Received:`);
366
+ lines.push(` Last 24 hours: ${stats.recentlyReceived.last24h}`);
367
+ lines.push(` Last 7 days: ${stats.recentlyReceived.last7d}`);
368
+ lines.push(` Last 30 days: ${stats.recentlyReceived.last30d}`);
369
+ lines.push(``);
370
+ }
371
+ if (stats.accounts.length > 0) {
372
+ lines.push(`📁 By Account:`);
373
+ for (const account of stats.accounts) {
374
+ lines.push(` ${account.name}: ${account.totalMessages} messages (${account.unreadMessages} unread)`);
375
+ }
376
+ }
377
+ return successResponse(lines.join("\n"));
378
+ }, "Error getting mail statistics"));
379
+ // --- get-sync-status ---
380
+ server.tool("get-sync-status", {}, withErrorHandling(() => {
381
+ const status = mailManager.getSyncStatus();
382
+ const lines = [];
383
+ lines.push(`🔄 Mail Sync Status`);
384
+ lines.push(`═══════════════════`);
385
+ if (status.error) {
386
+ lines.push(`Status: ⚠️ ${status.error}`);
387
+ }
388
+ else {
389
+ lines.push(`Mail.app: ${status.recentActivity ? "Running" : "Not running"}`);
390
+ lines.push(`Sync active: ${status.syncDetected ? "Yes" : "No"}`);
391
+ }
392
+ return successResponse(lines.join("\n"));
393
+ }, "Error getting sync status"));
394
+ // =============================================================================
395
+ // Server Startup
396
+ // =============================================================================
397
+ /**
398
+ * Initialize and start the MCP server.
399
+ */
400
+ const transport = new StdioServerTransport();
401
+ await server.connect(transport);
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Apple Mail Manager
3
+ *
4
+ * Handles all interactions with Apple Mail via AppleScript.
5
+ * This is the core service layer for the MCP server.
6
+ *
7
+ * Architecture:
8
+ * - Text escaping is handled by dedicated helper functions
9
+ * - AppleScript generation uses template builders for consistency
10
+ * - All public methods return typed results (no raw strings)
11
+ * - Error handling is consistent across all operations
12
+ *
13
+ * @module services/appleMailManager
14
+ */
15
+ import type { Message, MessageContent, Mailbox, Account, Attachment, HealthCheckResult, MailStats, BatchOperationResult, SyncStatus, RecentlyReceivedStats } from "../types.js";
16
+ /**
17
+ * Manager class for Apple Mail operations.
18
+ *
19
+ * Provides methods for:
20
+ * - Reading and searching messages
21
+ * - Sending emails
22
+ * - Managing mailboxes
23
+ * - Listing accounts
24
+ *
25
+ * All operations are synchronous since they rely on AppleScript
26
+ * execution via osascript. Error handling is consistent: methods
27
+ * return null/false/empty-array on failure rather than throwing.
28
+ */
29
+ export declare class AppleMailManager {
30
+ /**
31
+ * Default account used when no account is specified.
32
+ */
33
+ private defaultAccount;
34
+ /**
35
+ * Resolves the account to use for an operation.
36
+ * Falls back to first available account if not specified.
37
+ */
38
+ private resolveAccount;
39
+ /**
40
+ * Resolves a mailbox name to its actual name in the account.
41
+ *
42
+ * Different account types (IMAP, Exchange, iCloud) use different
43
+ * mailbox naming conventions:
44
+ * - IMAP/Gmail: "INBOX", "Sent", "Drafts"
45
+ * - Exchange: "Inbox", "Sent Items", "Deleted Items"
46
+ * - iCloud: "INBOX", "Sent", "Trash"
47
+ *
48
+ * This method tries to find a matching mailbox by:
49
+ * 1. Exact match
50
+ * 2. Case-insensitive match
51
+ * 3. Known aliases (e.g., "Sent" -> "Sent Items")
52
+ *
53
+ * @param mailbox - Requested mailbox name
54
+ * @param account - Account to search in
55
+ * @returns Actual mailbox name, or original if not found
56
+ */
57
+ private resolveMailbox;
58
+ /**
59
+ * Search for messages matching criteria.
60
+ *
61
+ * @param query - Text to search for in subject or sender
62
+ * @param mailbox - Mailbox to search in (e.g., "INBOX")
63
+ * @param account - Account to search in
64
+ * @param limit - Maximum number of results
65
+ * @returns Array of matching messages
66
+ */
67
+ searchMessages(query?: string, mailbox?: string, account?: string, limit?: number): Message[];
68
+ /**
69
+ * Get a message by ID.
70
+ *
71
+ * Note: Mail.app message IDs are unique per mailbox. This method searches
72
+ * all mailboxes in all accounts to find the message.
73
+ */
74
+ getMessageById(id: string): Message | null;
75
+ /**
76
+ * Get the content of a message.
77
+ */
78
+ getMessageContent(id: string): MessageContent | null;
79
+ /**
80
+ * List messages in a mailbox.
81
+ *
82
+ * @param mailbox - Mailbox to list from (default: INBOX)
83
+ * @param account - Account to list from
84
+ * @param limit - Maximum number of messages
85
+ * @returns Array of messages
86
+ */
87
+ listMessages(mailbox?: string, account?: string, limit?: number): Message[];
88
+ /**
89
+ * Parse message list output from AppleScript.
90
+ */
91
+ private parseMessageList;
92
+ /**
93
+ * Send an email.
94
+ *
95
+ * @param to - Recipient email addresses
96
+ * @param subject - Email subject
97
+ * @param body - Email body (plain text)
98
+ * @param cc - CC recipients
99
+ * @param bcc - BCC recipients
100
+ * @param account - Account to send from
101
+ * @returns true if sent successfully
102
+ */
103
+ sendEmail(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string): boolean;
104
+ /**
105
+ * Create a draft email (saved to Drafts folder, not sent).
106
+ *
107
+ * @param to - Recipient email addresses
108
+ * @param subject - Email subject
109
+ * @param body - Email body (plain text)
110
+ * @param cc - CC recipients
111
+ * @param bcc - BCC recipients
112
+ * @param account - Account to create draft in
113
+ * @returns true if draft created successfully
114
+ */
115
+ createDraft(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string): boolean;
116
+ /**
117
+ * Reply to a message.
118
+ *
119
+ * @param id - Message ID to reply to
120
+ * @param body - Reply body
121
+ * @param replyAll - If true, reply to all recipients
122
+ * @param send - If true, send immediately; if false, save as draft
123
+ * @returns true if reply created/sent successfully
124
+ */
125
+ replyToMessage(id: string, body: string, replyAll?: boolean, send?: boolean): boolean;
126
+ /**
127
+ * Forward a message.
128
+ *
129
+ * @param id - Message ID to forward
130
+ * @param to - Recipients to forward to
131
+ * @param body - Optional body to prepend
132
+ * @param send - If true, send immediately; if false, save as draft
133
+ * @returns true if forward created/sent successfully
134
+ */
135
+ forwardMessage(id: string, to: string[], body?: string, send?: boolean): boolean;
136
+ /**
137
+ * Helper to find and operate on a message by ID.
138
+ */
139
+ private findMessageScript;
140
+ /**
141
+ * Mark a message as read.
142
+ */
143
+ markAsRead(id: string): boolean;
144
+ /**
145
+ * Mark a message as unread.
146
+ */
147
+ markAsUnread(id: string): boolean;
148
+ /**
149
+ * Flag a message.
150
+ */
151
+ flagMessage(id: string): boolean;
152
+ /**
153
+ * Unflag a message.
154
+ */
155
+ unflagMessage(id: string): boolean;
156
+ /**
157
+ * Delete a message.
158
+ */
159
+ deleteMessage(id: string): boolean;
160
+ /**
161
+ * Move a message to a different mailbox.
162
+ */
163
+ moveMessage(id: string, mailbox: string, account?: string): boolean;
164
+ /**
165
+ * Delete multiple messages at once.
166
+ *
167
+ * @param ids - Array of message IDs to delete
168
+ * @returns Array of results for each message
169
+ */
170
+ batchDeleteMessages(ids: string[]): BatchOperationResult[];
171
+ /**
172
+ * Move multiple messages to a mailbox at once.
173
+ *
174
+ * @param ids - Array of message IDs to move
175
+ * @param mailbox - Destination mailbox name
176
+ * @param account - Account containing the destination mailbox
177
+ * @returns Array of results for each message
178
+ */
179
+ batchMoveMessages(ids: string[], mailbox: string, account?: string): BatchOperationResult[];
180
+ /**
181
+ * Mark multiple messages as read at once.
182
+ *
183
+ * @param ids - Array of message IDs to mark as read
184
+ * @returns Array of results for each message
185
+ */
186
+ batchMarkAsRead(ids: string[]): BatchOperationResult[];
187
+ /**
188
+ * List attachments for a message.
189
+ */
190
+ listAttachments(id: string): Attachment[];
191
+ /**
192
+ * List all mailboxes for an account.
193
+ */
194
+ listMailboxes(account?: string): Mailbox[];
195
+ /**
196
+ * Get unread count for a mailbox.
197
+ */
198
+ getUnreadCount(mailbox?: string, account?: string): number;
199
+ /**
200
+ * List all mail accounts.
201
+ */
202
+ listAccounts(): Account[];
203
+ /**
204
+ * Run health check on Mail.app connectivity.
205
+ */
206
+ healthCheck(): HealthCheckResult;
207
+ /**
208
+ * Get mail statistics.
209
+ */
210
+ getMailStats(): MailStats;
211
+ /**
212
+ * Get counts of recently received messages.
213
+ *
214
+ * Only counts messages in INBOX for performance (scanning all mailboxes
215
+ * is too slow for large accounts).
216
+ *
217
+ * @returns Counts of messages received in last 24h, 7d, and 30d
218
+ */
219
+ getRecentlyReceivedStats(): RecentlyReceivedStats;
220
+ /**
221
+ * Get sync status for Mail.app.
222
+ *
223
+ * Checks for sync activity indicators like:
224
+ * - Activity monitor status
225
+ * - Network activity status
226
+ * - Background refresh indicators
227
+ *
228
+ * @returns Sync status information
229
+ */
230
+ getSyncStatus(): SyncStatus;
231
+ }
232
+ //# sourceMappingURL=appleMailManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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"}