send_email
Send new emails directly from Mail.app using an existing account. Specify recipient, subject, body, and optionally CC and sender account.
Instructions
Send a new email via Mail.app from an existing account.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Primary recipient email address | |
| cc | No | CC recipient email address | |
| subject | Yes | ||
| body | Yes | ||
| from_account | No | Account name to send from (matches Mail.app account name) |
Implementation Reference
- src/tools/send.ts:33-52 (handler)The send_email tool handler function. Registers the tool on the MCP server, passes schema-validated arguments (to, cc, subject, body, from_account) to the AppleScript runner, and returns a confirmation message.
export function register(server: McpServer): void { server.tool( "send_email", "Send a new email via Mail.app from an existing account.", schema, { title: "Send Email", readOnlyHint: false, destructiveHint: true }, async ({ to, cc, subject, body, from_account }) => { await runAppleScript({ script: SCRIPT, args: { theTo: to, theCc: cc ?? "", theSubject: subject, theBody: body, fromAccount: from_account ?? "", }, }); return { content: [{ type: "text", text: `Email sent to ${to}` }] }; }, ); - src/tools/send.ts:5-14 (schema)Zod schema defining the input parameters for send_email: to (required string), cc (optional string), subject (required string), body (required string), from_account (optional string with description).
const schema = { to: z.string().describe("Primary recipient email address"), cc: z.string().optional().describe("CC recipient email address"), subject: z.string(), body: z.string(), from_account: z .string() .optional() .describe("Account name to send from (matches Mail.app account name)"), }; - src/server.ts:9-29 (registration)Import of the send tool's register function and registration on the MCP server at line 29.
import { register as registerSend } from "./tools/send.js"; import { register as registerReply } from "./tools/reply.js"; import { register as registerFlags } from "./tools/flags.js"; import { register as registerMove } from "./tools/move.js"; import { register as registerTrash } from "./tools/trash.js"; import { register as registerCreateMailbox } from "./tools/create_mailbox.js"; import { register as registerBulkMarkRead } from "./tools/bulk_mark_read.js"; import { register as registerGetUnsubscribeLink } from "./tools/get_unsubscribe_link.js"; import { register as registerListSenders } from "./tools/list_senders.js"; import { register as registerEmptyMailbox } from "./tools/empty_mailbox.js"; const server = new McpServer({ name: "mail-app-mcp", version: "1.0.0", }); registerSearch(server); registerRead(server); registerAccounts(server); registerListRecent(server); registerSend(server); - src/tools/send.ts:16-31 (helper)The AppleScript that constructs and sends an email via Mail.app. Creates an outgoing message, sets the sender if provided, adds to/cc recipients, then sends.
const SCRIPT = ` tell application "Mail" set newMsg to make new outgoing message with properties {subject:theSubject, content:theBody, visible:false} if fromAccount is not "" then set sender of newMsg to fromAccount end if tell newMsg make new to recipient at end of to recipients with properties {address:theTo} if theCc is not "" then make new cc recipient at end of cc recipients with properties {address:theCc} end if end tell send newMsg end tell return "sent" `; - src/lib/applescript.ts:22-46 (helper)The runAppleScript utility function that writes the script to a temp file and executes it via osascript, passing arguments safely through argv (no string interpolation).
export async function runAppleScript(opts: RunAppleScriptOptions): Promise<string> { const { script, args = {}, timeoutMs = 30_000 } = opts; const argNames = Object.keys(args); const argValues = argNames.map((n) => args[n]!); const bindings = argNames .map((name, i) => ` set ${name} to item ${i + 1} of argv`) .join("\n"); const wrapped = `on run argv\n${bindings}\n${script}\nend run\n`; const dir = await mkdtemp(path.join(tmpdir(), "mail-mcp-")); const scriptPath = path.join(dir, "script.applescript"); try { await writeFile(scriptPath, wrapped, "utf8"); const { stdout } = await execFileP("osascript", [scriptPath, ...argValues], { timeout: timeoutMs, maxBuffer: 10 * 1024 * 1024, }); return stdout.trimEnd(); } finally { await rm(dir, { recursive: true, force: true }).catch(() => {}); } }