advanced_search
Search Fastmail emails using multiple filters like sender, recipient, date ranges, attachments, and read status to find specific messages.
Instructions
Advanced email search with multiple criteria
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Text to search for in subject/body | |
| from | No | Filter by sender email | |
| to | No | Filter by recipient email | |
| subject | No | Filter by subject | |
| hasAttachment | No | Filter emails with attachments | |
| isUnread | No | Filter unread emails | |
| mailboxId | No | Search within specific mailbox | |
| after | No | Emails after this date (ISO 8601) | |
| before | No | Emails before this date (ISO 8601) | |
| limit | No | Maximum results (default: 50) |
Implementation Reference
- src/index.ts:1012-1026 (handler)MCP tool handler for 'advanced_search' that destructures input arguments, initializes JmapClient, calls advancedSearch method, and returns JSON-formatted email results.case 'advanced_search': { const { query, from, to, subject, hasAttachment, isUnread, mailboxId, after, before, limit } = args as any; const client = initializeClient(); const emails = await client.advancedSearch({ query, from, to, subject, hasAttachment, isUnread, mailboxId, after, before, limit }); return { content: [ { type: 'text', text: JSON.stringify(emails, null, 2), }, ], }; }
- src/index.ts:485-533 (schema)Input schema definition for the advanced_search tool, specifying all filter parameters and types.name: 'advanced_search', description: 'Advanced email search with multiple criteria', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Text to search for in subject/body', }, from: { type: 'string', description: 'Filter by sender email', }, to: { type: 'string', description: 'Filter by recipient email', }, subject: { type: 'string', description: 'Filter by subject', }, hasAttachment: { type: 'boolean', description: 'Filter emails with attachments', }, isUnread: { type: 'boolean', description: 'Filter unread emails', }, mailboxId: { type: 'string', description: 'Search within specific mailbox', }, after: { type: 'string', description: 'Emails after this date (ISO 8601)', }, before: { type: 'string', description: 'Emails before this date (ISO 8601)', }, limit: { type: 'number', description: 'Maximum results (default: 50)', default: 50, }, }, }, },
- src/index.ts:485-533 (registration)The tool definition object registered in the tools array passed to server.setTools().name: 'advanced_search', description: 'Advanced email search with multiple criteria', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Text to search for in subject/body', }, from: { type: 'string', description: 'Filter by sender email', }, to: { type: 'string', description: 'Filter by recipient email', }, subject: { type: 'string', description: 'Filter by subject', }, hasAttachment: { type: 'boolean', description: 'Filter emails with attachments', }, isUnread: { type: 'boolean', description: 'Filter unread emails', }, mailboxId: { type: 'string', description: 'Search within specific mailbox', }, after: { type: 'string', description: 'Emails after this date (ISO 8601)', }, before: { type: 'string', description: 'Emails before this date (ISO 8601)', }, limit: { type: 'number', description: 'Maximum results (default: 50)', default: 50, }, }, }, },
- src/jmap-client.ts:499-551 (helper)Supporting JmapClient method that constructs complex JMAP Email/query filter based on input parameters and fetches matching emails with relevant properties.async advancedSearch(filters: { query?: string; from?: string; to?: string; subject?: string; hasAttachment?: boolean; isUnread?: boolean; mailboxId?: string; after?: string; before?: string; limit?: number; }): Promise<any[]> { const session = await this.getSession(); // Build JMAP filter object const filter: any = {}; if (filters.query) filter.text = filters.query; if (filters.from) filter.from = filters.from; if (filters.to) filter.to = filters.to; if (filters.subject) filter.subject = filters.subject; if (filters.hasAttachment !== undefined) filter.hasAttachment = filters.hasAttachment; if (filters.isUnread !== undefined) filter.hasKeyword = filters.isUnread ? undefined : '$seen'; if (filters.mailboxId) filter.inMailbox = filters.mailboxId; if (filters.after) filter.after = filters.after; if (filters.before) filter.before = filters.before; // If unread filter is specifically true, we need to check for absence of $seen if (filters.isUnread === true) { filter.notKeyword = '$seen'; delete filter.hasKeyword; } const request: JmapRequest = { using: ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:mail'], methodCalls: [ ['Email/query', { accountId: session.accountId, filter, sort: [{ property: 'receivedAt', isAscending: false }], limit: Math.min(filters.limit || 50, 100) }, 'query'], ['Email/get', { accountId: session.accountId, '#ids': { resultOf: 'query', name: 'Email/query', path: '/ids' }, properties: ['id', 'subject', 'from', 'to', 'cc', 'receivedAt', 'preview', 'hasAttachment', 'keywords', 'threadId'] }, 'emails'] ] }; const response = await this.makeRequest(request); return response.methodResponses[1][1].list; }