fetch-emails
Retrieve emails from your inbox using filters for subject, date range, and sender to find specific messages quickly.
Instructions
Get emails from the user's inbox. Can specify the mailbox (INBOX by default), a subject (string), date range (ISO format: YYYY-MM-DDTHH:mm:ss), and sender emails (list of strings) to filter emails.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mailbox | No | Mailbox to fetch emails from | INBOX |
| subject | No | Optional subject to filter emails by subject or sender. Only sent if user provides a subject to search EXPLICITLY! | |
| dateRange | Yes | Date range is a dictionary with the keys "start" and "end". Must be provided on date time ISO string format. | |
| senders | No | Optional array of email addresses to filter emails by sender |
Implementation Reference
- src/tools/email.ts:30-84 (registration)Registration of the 'fetch-emails' MCP tool, including schema references and inline handler function.server.registerTool( "fetch-emails", { title: "Fetch Emails", description: "Get emails from the user's inbox. Can specify the mailbox (INBOX by default), a subject (string), date range (ISO format: YYYY-MM-DDTHH:mm:ss), and sender emails (list of strings) to filter emails.", inputSchema: FetchEmailsInputSchema.shape, outputSchema: FetchEmailsOutputSchema.shape, }, async (params, { requestInfo }) => { const authEmail = { port: requestInfo?.headers["email-port"], email: requestInfo?.headers["email-username"], password: requestInfo?.headers["email-password"], clientType: requestInfo?.headers["email-client-type"], } as AuthEmailType; const emailClient = new EmailClient(authEmail); const response = await emailClient.fetchEmails(params); if (response.error) { return { isError: true, content: [ { type: "text", text: response.error, }, ], }; } const instructionsPromptSource = requestInfo?.headers["email-instructions"] || process.env.EMAIL_INSTRUCTIONS || FETCH_EMAILS_PROMPT; const instructionsPrompt = await getResource( instructionsPromptSource as string ); const finalResponse = parseResponsePrompt(response, instructionsPrompt); return { content: [ { type: "text", text: finalResponse, }, ], structuredContent: response, }; } );
- src/models/email.ts:79-222 (handler)Core handler logic for fetching emails using IMAPFlow, including search criteria, fetching messages, and parsing envelopes.async fetchEmails(params: FetchEmailsInputType) { const client = this.getClient(); try { await client.connect(); await client.mailboxOpen(params.mailbox || "INBOX"); const defaultStartDate = DateTime.now().startOf("day"); const defaultEndDate = DateTime.now().endOf("day"); const orConditions: Array<{ from: string }> = []; if (params.senders) { for (const sender of params.senders) { orConditions.push({ from: sender }); } } const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; if (params.dateRange.start) { params.dateRange.start = params.dateRange.start.replace( /Z|GMT-[0-9]+/g, "" ); // if no time is provided, set to start of day if (!params.dateRange.start.includes("T")) { params.dateRange.start += "T00:00:00"; } } if (params.dateRange.end) { params.dateRange.end = params.dateRange.end.replace( /Z|GMT-[0-9]+/g, "" ); // if no time is provided, set to end of day if (!params.dateRange.end.includes("T")) { params.dateRange.end += "T23:59:59"; } } let sinceDate = params.dateRange.start ? DateTime.fromISO(params.dateRange.start) : defaultStartDate; let beforeDate = params.dateRange.end ? DateTime.fromISO(params.dateRange.end) : defaultEndDate; if (params.dateRange.start) { sinceDate = sinceDate.setZone(localTimezone, { keepLocalTime: true }); } if (params.dateRange.end) { beforeDate = beforeDate.setZone(localTimezone, { keepLocalTime: true }); } const searchCriteria: SearchObject = { subject: params.subject, since: sinceDate.toJSDate(), before: beforeDate.toJSDate(), or: orConditions.length > 0 ? orConditions : undefined, }; Logger.debug( "Searching emails with criteria:", JSON.stringify(searchCriteria, null, 2) ); const messagesUIDs = await client.search(searchCriteria, { uid: true, }); if (!messagesUIDs) { return { emails: [], error: "No emails found matching the criteria.", }; } Logger.debug(`Found ${messagesUIDs.length} emails matching the criteria`); const emailsParsed: FetchEmailsOutputType["emails"] = []; for (const messageUID of messagesUIDs) { const message = await client.fetchOne( messageUID, { uid: true, envelope: true, bodyStructure: true, }, { uid: true, } ); if (!message) { continue; } if (message.envelope?.date) { const emailDate = DateTime.fromJSDate(message.envelope.date); const isInRange = emailDate >= sinceDate && emailDate < beforeDate; if (!isInRange) { continue; } } const senderParsed = message.envelope?.sender ?.map((s) => { const { address, name } = s; return name ? `${name} <${address}>` : address; }) .join(", ") || "Unknown Sender"; emailsParsed.push({ id: messageUID, subject: message.envelope?.subject || "No Subject", sender: senderParsed, snippet: "", date: message.envelope?.date ? DateTime.fromJSDate(message.envelope.date).toISO() : undefined, }); } Logger.info(`Parsed ${emailsParsed.length} emails successfully`); return { emails: emailsParsed, }; } catch (error) { Logger.error( "Error fetching emails:", error instanceof Error ? error.message : "Unknown error" ); return { emails: [], error: "Failed to fetch emails" }; } finally { await client.mailboxClose(); await client.logout(); } }
- src/types/email.ts:27-47 (schema)Zod schema for input parameters of the fetch-emails tool.export const FetchEmailsInputSchema = z.object({ mailbox: z.string().default("INBOX").describe("Mailbox to fetch emails from"), subject: z .string() .optional() .describe( "Optional subject to filter emails by subject or sender. Only sent if user provides a subject to search EXPLICITLY!" ), dateRange: z .object({ start: z.string().optional().describe("Start date of the range"), end: z.string().optional().describe("End date of the range"), }) .describe( 'Date range is a dictionary with the keys "start" and "end". Must be provided on date time ISO string format.' ), senders: z .array(z.string()) .optional() .describe("Optional array of email addresses to filter emails by sender"), });
- src/types/email.ts:50-64 (schema)Zod schema for output of the fetch-emails tool.export const FetchEmailsOutputSchema = z.object({ emails: z .array( z.object({ id: z.number(), subject: z.string(), sender: z.string(), snippet: z.string(), date: z.string().nullish(), }) ) .nullish(), error: z.string().nullish(), }); export type FetchEmailsOutputType = z.infer<typeof FetchEmailsOutputSchema>;
- src/tools/email.ts:13-27 (helper)Helper function to parse and format the email response into the prompt template.const parseResponsePrompt = ( response: FetchEmailsOutputType, prompt: string ) => { if (!response.emails || response.emails.length === 0) { return prompt.replace("{{emails}}", "[]"); } const emailsContent = prompt.replace( "{{emails}}", JSON.stringify(response.emails) ); return emailsContent; };