appleMailManager.d.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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, MailRule, Contact, EmailTemplate, SerialEmailRecipient, SerialEmailResult } 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. * TTL cache for expensive AppleScript queries that rarely change.
  36. * Caches account list and per-account mailbox names to avoid
  37. * redundant AppleScript roundtrips on every tool call.
  38. */
  39. private cache;
  40. /** Cache TTL in milliseconds (60 seconds). */
  41. private readonly CACHE_TTL_MS;
  42. /**
  43. * Returns cached accounts or fetches fresh data if cache is expired/empty.
  44. */
  45. private getCachedAccounts;
  46. /**
  47. * Returns cached mailbox names for an account, or fetches fresh.
  48. * This caches only the name list used by resolveMailbox(), not the
  49. * full Mailbox objects with counts (which change frequently).
  50. */
  51. private getCachedMailboxNames;
  52. /**
  53. * Invalidate all caches. Call after operations that change
  54. * mailbox structure (create/delete/rename mailbox).
  55. */
  56. private invalidateCache;
  57. /**
  58. * Resolves the account to use for an operation.
  59. * Queries Mail.app's configured default send account, then falls back
  60. * to the first available account.
  61. */
  62. private resolveAccount;
  63. /**
  64. * Resolves a mailbox name to its actual name in the account.
  65. *
  66. * Different account types (IMAP, Exchange, iCloud) use different
  67. * mailbox naming conventions:
  68. * - IMAP/Gmail: "INBOX", "Sent", "Drafts"
  69. * - Exchange: "Inbox", "Sent Items", "Deleted Items"
  70. * - iCloud: "INBOX", "Sent", "Trash"
  71. *
  72. * This method tries to find a matching mailbox by:
  73. * 1. Exact match
  74. * 2. Case-insensitive match
  75. * 3. Known aliases (e.g., "Sent" -> "Sent Items")
  76. *
  77. * @param mailbox - Requested mailbox name
  78. * @param account - Account to search in
  79. * @returns Actual mailbox name, or original if not found
  80. */
  81. private resolveMailbox;
  82. /**
  83. * Search for messages matching criteria.
  84. *
  85. * @param query - Text to search for in subject or sender
  86. * @param mailbox - Mailbox to search in (e.g., "INBOX")
  87. * @param account - Account to search in
  88. * @param limit - Maximum number of results
  89. * @returns Array of matching messages
  90. */
  91. searchMessages(query?: string, mailbox?: string, account?: string, limit?: number, dateFrom?: string, dateTo?: string): Message[];
  92. /**
  93. * Get a message by ID.
  94. *
  95. * Note: Mail.app message IDs are unique per mailbox. This method searches
  96. * all mailboxes in all accounts to find the message.
  97. */
  98. getMessageById(id: string): Message | null;
  99. /**
  100. * Get the content of a message.
  101. */
  102. getMessageContent(id: string): MessageContent | null;
  103. /**
  104. * Get the raw MIME source of a message.
  105. * Used as fallback for attachment extraction when AppleScript
  106. * mail attachments returns empty.
  107. *
  108. * Timeout is 2x the default (120s) because `source of msg` returns
  109. * the entire raw message including base64-encoded attachments —
  110. * a 20MB attachment can take several seconds over Exchange/IMAP.
  111. */
  112. getRawSource(id: string): string | null;
  113. /**
  114. * List messages in a mailbox.
  115. *
  116. * @param mailbox - Mailbox to list from (default: INBOX)
  117. * @param account - Account to list from
  118. * @param limit - Maximum number of messages
  119. * @returns Array of messages
  120. */
  121. listMessages(mailbox?: string, account?: string, limit?: number, from?: string, offset?: number): Message[];
  122. /**
  123. * Parse message list output from AppleScript.
  124. *
  125. * Two emission schemas, disambiguated by length:
  126. * 7 fields: single-mailbox — ...|hasAtt (mailbox from caller)
  127. * 8 fields: all-mailboxes — ...|mailbox|hasAtt
  128. *
  129. * `hasAttachments` here is the fast-path AppleScript count only; it will
  130. * false-negative for MIME-embedded attachments (a known AppleScript
  131. * limitation). Use getMessage or list-attachments for authoritative info.
  132. */
  133. private parseMessageList;
  134. /**
  135. * Send an email.
  136. *
  137. * @param to - Recipient email addresses
  138. * @param subject - Email subject
  139. * @param body - Email body (plain text)
  140. * @param cc - CC recipients
  141. * @param bcc - BCC recipients
  142. * @param account - Account to send from
  143. * @returns true if sent successfully
  144. */
  145. sendEmail(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string, attachments?: string[]): boolean;
  146. /**
  147. * Send individual personalized emails to a list of recipients (mail merge).
  148. *
  149. * Replaces {{placeholder}} tokens in subject and body with per-recipient values.
  150. * Each recipient receives their own individual email.
  151. *
  152. * @param recipients - List of recipient objects with email and variable values
  153. * @param subject - Email subject (may contain {{placeholders}})
  154. * @param body - Email body (may contain {{placeholders}})
  155. * @param account - Account to send from
  156. * @param delayMs - Delay between sends in milliseconds (default: 500, max: 10000)
  157. * @returns Array of per-recipient results
  158. */
  159. sendSerialEmail(recipients: SerialEmailRecipient[], subject: string, body: string, account?: string, delayMs?: number): SerialEmailResult[];
  160. /**
  161. * Create a draft email (saved to Drafts folder, not sent).
  162. *
  163. * @param to - Recipient email addresses
  164. * @param subject - Email subject
  165. * @param body - Email body (plain text)
  166. * @param cc - CC recipients
  167. * @param bcc - BCC recipients
  168. * @param account - Account to create draft in
  169. * @returns true if draft created successfully
  170. */
  171. createDraft(to: string[], subject: string, body: string, cc?: string[], bcc?: string[], account?: string, attachments?: string[]): boolean;
  172. /**
  173. * Reply to a message.
  174. *
  175. * @param id - Message ID to reply to
  176. * @param body - Reply body
  177. * @param replyAll - If true, reply to all recipients
  178. * @param send - If true, send immediately; if false, save as draft
  179. * @returns true if reply created/sent successfully
  180. */
  181. replyToMessage(id: string, body: string, replyAll?: boolean, send?: boolean): boolean;
  182. /**
  183. * Forward a message.
  184. *
  185. * @param id - Message ID to forward
  186. * @param to - Recipients to forward to
  187. * @param body - Optional body to prepend
  188. * @param send - If true, send immediately; if false, save as draft
  189. * @returns true if forward created/sent successfully
  190. */
  191. forwardMessage(id: string, to: string[], body?: string, send?: boolean): boolean;
  192. /**
  193. * Helper to find and operate on a message by ID.
  194. */
  195. private findMessageScript;
  196. /**
  197. * Mark a message as read.
  198. */
  199. markAsRead(id: string): boolean;
  200. /**
  201. * Mark a message as unread.
  202. */
  203. markAsUnread(id: string): boolean;
  204. /**
  205. * Flag a message.
  206. */
  207. flagMessage(id: string): boolean;
  208. /**
  209. * Unflag a message.
  210. */
  211. unflagMessage(id: string): boolean;
  212. /**
  213. * Delete a message.
  214. */
  215. deleteMessage(id: string): boolean;
  216. /**
  217. * Move a message to a different mailbox.
  218. */
  219. moveMessage(id: string, mailbox: string, account?: string): boolean;
  220. /**
  221. * Delete multiple messages at once.
  222. *
  223. * @param ids - Array of message IDs to delete
  224. * @returns Array of results for each message
  225. */
  226. batchDeleteMessages(ids: string[]): BatchOperationResult[];
  227. /**
  228. * Move multiple messages to a mailbox at once.
  229. *
  230. * @param ids - Array of message IDs to move
  231. * @param mailbox - Destination mailbox name
  232. * @param account - Account containing the destination mailbox
  233. * @returns Array of results for each message
  234. */
  235. batchMoveMessages(ids: string[], mailbox: string, account?: string): BatchOperationResult[];
  236. /**
  237. * Mark multiple messages as read at once.
  238. */
  239. batchMarkAsRead(ids: string[]): BatchOperationResult[];
  240. /**
  241. * Mark multiple messages as unread at once.
  242. */
  243. batchMarkAsUnread(ids: string[]): BatchOperationResult[];
  244. /**
  245. * Flag multiple messages at once.
  246. */
  247. batchFlagMessages(ids: string[]): BatchOperationResult[];
  248. /**
  249. * Unflag multiple messages at once.
  250. */
  251. batchUnflagMessages(ids: string[]): BatchOperationResult[];
  252. /**
  253. * List attachments for a message.
  254. * Tries AppleScript first, falls back to MIME source parsing
  255. * when AppleScript returns empty (known issue across all account types).
  256. */
  257. listAttachments(id: string): Attachment[];
  258. /**
  259. * Save an attachment from a message to disk.
  260. * Tries AppleScript first, falls back to MIME source extraction
  261. * when AppleScript can't find the attachment.
  262. */
  263. saveAttachment(id: string, attachmentName: string, savePath: string): boolean;
  264. /**
  265. * List all mailboxes for an account.
  266. */
  267. listMailboxes(account?: string): Mailbox[];
  268. /**
  269. * Get unread count for a mailbox.
  270. */
  271. getUnreadCount(mailbox?: string, account?: string): number;
  272. /**
  273. * Create a new mailbox.
  274. */
  275. createMailbox(name: string, account?: string): boolean;
  276. /**
  277. * Delete a mailbox.
  278. */
  279. deleteMailbox(name: string, account?: string): boolean;
  280. /**
  281. * Rename a mailbox by creating a new one, moving messages, and deleting the old one.
  282. */
  283. renameMailbox(oldName: string, newName: string, account?: string): boolean;
  284. /**
  285. * List all mail accounts (uses cache).
  286. */
  287. listAccounts(): Account[];
  288. /**
  289. * Fetches account list directly from Mail.app via AppleScript.
  290. * Used internally by the cache; prefer getCachedAccounts() or listAccounts().
  291. */
  292. private fetchAccounts;
  293. /**
  294. * Fetches mailbox names for an account directly from Mail.app.
  295. * Used internally by the cache; prefer getCachedMailboxNames().
  296. */
  297. private fetchMailboxNames;
  298. /**
  299. * List all mail rules.
  300. */
  301. listRules(): MailRule[];
  302. /**
  303. * Enable or disable a mail rule.
  304. */
  305. setRuleEnabled(ruleName: string, enabled: boolean): boolean;
  306. /**
  307. * Search contacts by name or email.
  308. */
  309. searchContacts(query: string): Contact[];
  310. private templates;
  311. private nextTemplateId;
  312. /**
  313. * List all stored templates.
  314. */
  315. listTemplates(): EmailTemplate[];
  316. /**
  317. * Get a template by ID.
  318. */
  319. getTemplate(id: string): EmailTemplate | null;
  320. /**
  321. * Create or update a template.
  322. */
  323. saveTemplate(name: string, subject: string, body: string, to?: string[], cc?: string[], id?: string): EmailTemplate;
  324. /**
  325. * Delete a template.
  326. */
  327. deleteTemplate(id: string): boolean;
  328. /**
  329. * Use a template to create a draft.
  330. */
  331. useTemplate(id: string, overrides?: {
  332. to?: string[];
  333. cc?: string[];
  334. subject?: string;
  335. body?: string;
  336. }): boolean;
  337. /**
  338. * Run health check on Mail.app connectivity.
  339. */
  340. healthCheck(): HealthCheckResult;
  341. /**
  342. * Get mail statistics.
  343. */
  344. getMailStats(): MailStats;
  345. /**
  346. * Get counts of recently received messages.
  347. *
  348. * Only counts messages in INBOX for performance (scanning all mailboxes
  349. * is too slow for large accounts).
  350. *
  351. * @returns Counts of messages received in last 24h, 7d, and 30d
  352. */
  353. getRecentlyReceivedStats(): RecentlyReceivedStats;
  354. /**
  355. * Get sync status for Mail.app.
  356. *
  357. * Checks for sync activity indicators like:
  358. * - Activity monitor status
  359. * - Network activity status
  360. * - Background refresh indicators
  361. *
  362. * @returns Sync status information
  363. */
  364. getSyncStatus(): SyncStatus;
  365. }
  366. //# sourceMappingURL=appleMailManager.d.ts.map