mail_get_email
Retrieve specific emails from Mail.app by searching with criteria like sender, subject, date, or mailbox to locate messages without manual browsing.
Instructions
[Mail operations] Get a specific email by search criteria from Mail.app
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mailbox | No | Name of the mailbox to search in (e.g., 'Inbox', 'Sent') | Inbox |
| account | No | Name of the account to search in (e.g., 'iCloud', 'Gmail', 'Exchange'). If not specified, searches all accounts with preference for iCloud. | iCloud |
| subject | No | Subject text to search for (partial match) | |
| sender | No | Sender email or name to search for (partial match) | |
| dateReceived | No | Date received to search for (format: YYYY-MM-DD) | |
| unreadOnly | No | Only search unread emails if true | |
| includeBody | No | Include email body in the result if true |
Implementation Reference
- src/categories/mail.ts:385-605 (handler)Handler implementation for the 'get_email' tool (registered as 'mail_get_email'). Generates AppleScript to search Mail.app for emails matching criteria like subject, sender, date, mailbox, and optionally includes body.{ name: "get_email", description: "Get a specific email by search criteria from Mail.app", schema: { type: "object", properties: { mailbox: { type: "string", description: "Name of the mailbox to search in (e.g., 'Inbox', 'Sent')", default: "Inbox" }, account: { type: "string", description: "Name of the account to search in (e.g., 'iCloud', 'Gmail', 'Exchange'). If not specified, searches all accounts with preference for iCloud.", default: "iCloud" }, subject: { type: "string", description: "Subject text to search for (partial match)" }, sender: { type: "string", description: "Sender email or name to search for (partial match)" }, dateReceived: { type: "string", description: "Date received to search for (format: YYYY-MM-DD)" }, unreadOnly: { type: "boolean", description: "Only search unread emails if true" }, includeBody: { type: "boolean", description: "Include email body in the result if true", default: false } }, required: [] }, script: (args) => ` set mailboxName to "${args.mailbox || 'Inbox'}" set accountName to "${args.account || 'iCloud'}" set searchSubject to "${args.subject || ''}" set searchSender to "${args.sender || ''}" set searchDate to "${args.dateReceived || ''}" set showUnreadOnly to ${args.unreadOnly ? 'true' : 'false'} set includeBody to ${args.includeBody ? 'true' : 'false'} set searchAllAccounts to ${!args.account ? 'true' : 'false'} tell application "Mail" -- Get all messages if no specific mailbox is found set foundMailbox to false set emailMessages to {} set targetAccount to missing value -- First try to find the specified account if not searchAllAccounts then try set allAccounts to every account repeat with acct in allAccounts if name of acct is accountName then set targetAccount to acct exit repeat end if end repeat end try -- If account not found, set to search all accounts if targetAccount is missing value then set searchAllAccounts to true end if end if -- If specific account is found, search in that account if not searchAllAccounts and targetAccount is not missing value then try set acctMailboxes to every mailbox of targetAccount repeat with m in acctMailboxes if name of m is mailboxName then set targetMailbox to m set foundMailbox to true -- Get messages from the found mailbox if showUnreadOnly then set emailMessages to (messages of targetMailbox whose read status is false) else set emailMessages to (messages of targetMailbox) end if exit repeat end if end repeat end try else -- Search all accounts, with preference for iCloud set iCloudAccount to missing value set allAccounts to every account -- First look for iCloud account repeat with acct in allAccounts if name of acct is "iCloud" then set iCloudAccount to acct exit repeat end if end repeat -- Try to find the mailbox directly try set allMailboxes to every mailbox repeat with m in allMailboxes if name of m is mailboxName then set targetMailbox to m set foundMailbox to true -- Get messages from the found mailbox if showUnreadOnly then set emailMessages to (messages of targetMailbox whose read status is false) else set emailMessages to (messages of targetMailbox) end if exit repeat end if end repeat end try end if -- Filter messages based on search criteria set filteredMessages to {} repeat with theMessage in emailMessages try set matchesSubject to true set matchesSender to true set matchesDate to true -- Check subject if specified if searchSubject is not "" then set msgSubject to subject of theMessage if msgSubject does not contain searchSubject then set matchesSubject to false end if end if -- Check sender if specified if searchSender is not "" then set msgSender to sender of theMessage if msgSender does not contain searchSender then set matchesSender to false end if end if -- Check date if specified if searchDate is not "" then set msgDate to date received of theMessage set msgDateString to (year of msgDate as string) & "-" & my padNumber(month of msgDate as integer) & "-" & my padNumber(day of msgDate as integer) if msgDateString is not searchDate then set matchesDate to false end if end if -- Add to filtered list if all criteria match if matchesSubject and matchesSender and matchesDate then set end of filteredMessages to theMessage end if end try end repeat -- Format the results set emailList to "Search results:" & return & return if (count of filteredMessages) is 0 then set emailList to emailList & "No matching emails found." else repeat with theMessage in filteredMessages try set msgSubject to subject of theMessage set msgSender to sender of theMessage set msgDate to date received of theMessage set msgRead to read status of theMessage -- Try to get account name for this message set msgAccount to "" try set msgMailbox to mailbox of theMessage set msgAcct to account of msgMailbox set msgAccount to " [" & name of msgAcct & "]" end try set emailList to emailList & "From: " & msgSender & return set emailList to emailList & "Subject: " & msgSubject & return set emailList to emailList & "Date: " & msgDate & msgAccount & return set emailList to emailList & "Read: " & msgRead & return -- Include body if requested if includeBody then set msgContent to content of theMessage set emailList to emailList & "Content: " & return & msgContent & return end if set emailList to emailList & return on error errMsg set emailList to emailList & "Error processing message: " & errMsg & return & return end try end repeat end if return emailList end tell -- Helper function to pad numbers with leading zero if needed on padNumber(num) if num < 10 then return "0" & num else return num as string end if end padNumber `, },
- src/categories/mail.ts:388-424 (schema)Input schema for the mail_get_email tool, defining parameters for searching emails by mailbox, account, subject, sender, date, unread status, and body inclusion.schema: { type: "object", properties: { mailbox: { type: "string", description: "Name of the mailbox to search in (e.g., 'Inbox', 'Sent')", default: "Inbox" }, account: { type: "string", description: "Name of the account to search in (e.g., 'iCloud', 'Gmail', 'Exchange'). If not specified, searches all accounts with preference for iCloud.", default: "iCloud" }, subject: { type: "string", description: "Subject text to search for (partial match)" }, sender: { type: "string", description: "Sender email or name to search for (partial match)" }, dateReceived: { type: "string", description: "Date received to search for (format: YYYY-MM-DD)" }, unreadOnly: { type: "boolean", description: "Only search unread emails if true" }, includeBody: { type: "boolean", description: "Include email body in the result if true", default: false } }, required: [] },
- src/framework.ts:219-232 (registration)Registers all tools for listing, constructing names like 'mail_get_email' from category 'mail' and script 'get_email', including description and input schema.private setupHandlers(): void { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: this.categories.flatMap((category) => category.scripts.map((script) => ({ name: `${category.name}_${script.name}`, // Changed from dot to underscore description: `[${category.description}] ${script.description}`, inputSchema: script.schema || { type: "object", properties: {}, }, })), ), }));
- src/framework.ts:242-258 (registration)Tool execution handler parses tool name 'mail_get_email' by splitting on '_', finds 'mail' category and 'get_email' script, generates and executes the AppleScript.try { // Split on underscore instead of dot const [categoryName, ...scriptNameParts] = toolName.split("_"); const scriptName = scriptNameParts.join("_"); // Rejoin in case script name has underscores const category = this.categories.find((c) => c.name === categoryName); if (!category) { this.log("warning", "Category not found", { categoryName }); throw new McpError( ErrorCode.MethodNotFound, `Category not found: ${categoryName}`, ); } const script = category.scripts.find((s) => s.name === scriptName); if (!script) {
- src/index.ts:8-31 (registration)Imports and registers the mail category containing the get_email script, making 'mail_get_email' available as a tool.import { mailCategory } from "./categories/mail.js"; import { pagesCategory } from "./categories/pages.js"; import { shortcutsCategory } from "./categories/shortcuts.js"; import { messagesCategory } from "./categories/messages.js"; import { notesCategory } from "./categories/notes.js"; const server = new AppleScriptFramework({ name: "applescript-server", version: "1.0.4", debug: false, }); // Log startup information using stderr (server isn't connected yet) console.error(`[INFO] Starting AppleScript MCP server - PID: ${process.pid}`); // Add all categories console.error("[INFO] Registering categories..."); server.addCategory(systemCategory); server.addCategory(calendarCategory); server.addCategory(finderCategory); server.addCategory(clipboardCategory); server.addCategory(notificationsCategory); server.addCategory(itermCategory); server.addCategory(mailCategory);