Skip to main content
Glama
shuakami

Mail MCP Tool

by shuakami

searchEmails

Find emails in your inbox using keywords, date ranges, sender/recipient filters, and attachment criteria to locate specific messages quickly.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
keywordsNo
foldersNo
startDateNo
endDateNo
fromNo
toNo
subjectNo
hasAttachmentNo
maxResultsNo
includeBodyNo

Implementation Reference

  • Registration of the 'searchEmails' MCP tool, including Zod input schema and the handler function that performs advanced email search by calling mailService.advancedSearchMails and formats results.
    this.server.tool(
      "searchEmails",
      {
        keywords: z.string().optional(),
        folders: z.array(z.string()).optional(),
        startDate: z.union([z.date(), z.string().datetime({ message: "startDate 必须是有效的 ISO 8601 日期时间字符串或 Date 对象" })]).optional(),
        endDate: z.union([z.date(), z.string().datetime({ message: "endDate 必须是有效的 ISO 8601 日期时间字符串或 Date 对象" })]).optional(),
        from: z.string().optional(),
        to: z.string().optional(),
        subject: z.string().optional(),
        hasAttachment: z.boolean().optional(),
        maxResults: z.number().default(50),
        includeBody: z.boolean().default(false)
      },
      async (params) => {
        try {
          console.log(`开始执行高级邮件搜索,关键词: ${params.keywords || '无'}`);
          
          // 处理日期字符串
          const startDate = typeof params.startDate === 'string' ? new Date(params.startDate) : params.startDate;
          const endDate = typeof params.endDate === 'string' ? new Date(params.endDate) : params.endDate;
    
          const emails = await this.mailService.advancedSearchMails({
            folders: params.folders,
            keywords: params.keywords,
            startDate: startDate,
            endDate: endDate,
            from: params.from,
            to: params.to,
            subject: params.subject,
            hasAttachment: params.hasAttachment,
            maxResults: params.maxResults,
            includeBody: params.includeBody
          });
          
          // 转换为人类可读格式
          if (emails.length === 0) {
            return {
              content: [
                { type: "text", text: `没有找到符合条件的邮件。` }
              ]
            };
          }
          
          const searchTerms = [];
          if (params.keywords) searchTerms.push(`关键词"${params.keywords}"`);
          if (params.from) searchTerms.push(`发件人包含"${params.from}"`);
          if (params.to) searchTerms.push(`收件人包含"${params.to}"`);
          if (params.subject) searchTerms.push(`主题包含"${params.subject}"`);
          if (startDate) searchTerms.push(`开始日期${startDate.toLocaleDateString()}`);
          if (endDate) searchTerms.push(`结束日期${endDate.toLocaleDateString()}`);
          if (params.hasAttachment) searchTerms.push(`包含附件`);
          
          const searchDescription = searchTerms.length > 0 
            ? `搜索条件: ${searchTerms.join(', ')}` 
            : '所有邮件';
          
          let resultText = `🔍 邮件搜索结果 (${emails.length}封邮件)\n${searchDescription}\n\n`;
          
          emails.forEach((email, index) => {
            const fromStr = email.from.map(f => f.name ? `${f.name} <${f.address}>` : f.address).join(', ');
            const date = email.date.toLocaleString();
            const status = email.isRead ? '已读' : '未读';
            const attachmentInfo = email.hasAttachments ? '有' : '';
            const folder = email.folder;
            
            resultText += `${index + 1}. [${status}] ${attachmentInfo} 来自: ${fromStr}\n`;
            resultText += `   主题: ${email.subject}\n`;
            resultText += `   时间: ${date}\n`;
            resultText += `   文件夹: ${folder}\n`;
            resultText += `   UID: ${email.uid}\n\n`;
          });
          
          resultText += `使用 getEmailDetail 工具并提供 UID 和 folder 可以查看邮件详情。`;
          
          return {
            content: [
              { type: "text", text: resultText }
            ]
          };
        } catch (error) {
          return {
            content: [
              { type: "text", text: `搜索邮件时发生错误: ${error instanceof Error ? error.message : String(error)}` }
            ]
          };
        }
      }
    );
  • The handler function for the searchEmails tool, which invokes the mail service's advanced search and returns human-readable results.
      async (params) => {
        try {
          console.log(`开始执行高级邮件搜索,关键词: ${params.keywords || '无'}`);
          
          // 处理日期字符串
          const startDate = typeof params.startDate === 'string' ? new Date(params.startDate) : params.startDate;
          const endDate = typeof params.endDate === 'string' ? new Date(params.endDate) : params.endDate;
    
          const emails = await this.mailService.advancedSearchMails({
            folders: params.folders,
            keywords: params.keywords,
            startDate: startDate,
            endDate: endDate,
            from: params.from,
            to: params.to,
            subject: params.subject,
            hasAttachment: params.hasAttachment,
            maxResults: params.maxResults,
            includeBody: params.includeBody
          });
          
          // 转换为人类可读格式
          if (emails.length === 0) {
            return {
              content: [
                { type: "text", text: `没有找到符合条件的邮件。` }
              ]
            };
          }
          
          const searchTerms = [];
          if (params.keywords) searchTerms.push(`关键词"${params.keywords}"`);
          if (params.from) searchTerms.push(`发件人包含"${params.from}"`);
          if (params.to) searchTerms.push(`收件人包含"${params.to}"`);
          if (params.subject) searchTerms.push(`主题包含"${params.subject}"`);
          if (startDate) searchTerms.push(`开始日期${startDate.toLocaleDateString()}`);
          if (endDate) searchTerms.push(`结束日期${endDate.toLocaleDateString()}`);
          if (params.hasAttachment) searchTerms.push(`包含附件`);
          
          const searchDescription = searchTerms.length > 0 
            ? `搜索条件: ${searchTerms.join(', ')}` 
            : '所有邮件';
          
          let resultText = `🔍 邮件搜索结果 (${emails.length}封邮件)\n${searchDescription}\n\n`;
          
          emails.forEach((email, index) => {
            const fromStr = email.from.map(f => f.name ? `${f.name} <${f.address}>` : f.address).join(', ');
            const date = email.date.toLocaleString();
            const status = email.isRead ? '已读' : '未读';
            const attachmentInfo = email.hasAttachments ? '有' : '';
            const folder = email.folder;
            
            resultText += `${index + 1}. [${status}] ${attachmentInfo} 来自: ${fromStr}\n`;
            resultText += `   主题: ${email.subject}\n`;
            resultText += `   时间: ${date}\n`;
            resultText += `   文件夹: ${folder}\n`;
            resultText += `   UID: ${email.uid}\n\n`;
          });
          
          resultText += `使用 getEmailDetail 工具并提供 UID 和 folder 可以查看邮件详情。`;
          
          return {
            content: [
              { type: "text", text: resultText }
            ]
          };
        } catch (error) {
          return {
            content: [
              { type: "text", text: `搜索邮件时发生错误: ${error instanceof Error ? error.message : String(error)}` }
            ]
          };
        }
      }
    );
  • Zod schema defining input parameters for the searchEmails tool (keywords, folders, dates, from/to/subject filters, etc.).
      keywords: z.string().optional(),
      folders: z.array(z.string()).optional(),
      startDate: z.union([z.date(), z.string().datetime({ message: "startDate 必须是有效的 ISO 8601 日期时间字符串或 Date 对象" })]).optional(),
      endDate: z.union([z.date(), z.string().datetime({ message: "endDate 必须是有效的 ISO 8601 日期时间字符串或 Date 对象" })]).optional(),
      from: z.string().optional(),
      to: z.string().optional(),
      subject: z.string().optional(),
      hasAttachment: z.boolean().optional(),
      maxResults: z.number().default(50),
      includeBody: z.boolean().default(false)
    },
  • Helper method advancedSearchMails in MailService class that implements the core IMAP search logic across multiple folders with advanced filtering and keyword matching.
    async advancedSearchMails(options: {
      folders?: string[];        // 要搜索的文件夹列表,默认为INBOX
      keywords?: string;         // 全文搜索关键词
      startDate?: Date;          // 开始日期
      endDate?: Date;            // 结束日期
      from?: string;             // 发件人
      to?: string;               // 收件人
      subject?: string;          // 主题
      hasAttachment?: boolean;   // 是否有附件
      maxResults?: number;       // 最大结果数
      includeBody?: boolean;     // 是否包含邮件正文
    }): Promise<MailItem[]> {
      const allResults: MailItem[] = [];
      const folders = options.folders || ['INBOX'];
      const maxResults = options.maxResults || 100;
      
      console.log(`执行高级搜索,文件夹: ${folders.join(', ')}, 关键词: ${options.keywords || '无'}`);
      
      // 对每个文件夹执行搜索
      for (const folder of folders) {
        if (allResults.length >= maxResults) break;
        
        try {
          const folderResults = await this.searchMails({
            folder,
            readStatus: 'all',
            fromDate: options.startDate,
            toDate: options.endDate,
            from: options.from,
            to: options.to,
            subject: options.subject,
            hasAttachments: options.hasAttachment,
            limit: maxResults - allResults.length
          });
          
          // 如果包含关键词,执行全文匹配
          if (options.keywords && options.keywords.trim() !== '') {
            const keywordLower = options.keywords.toLowerCase();
            const filteredResults = folderResults.filter(mail => {
              // 在主题、发件人、收件人中搜索
              const subjectMatch = mail.subject.toLowerCase().includes(keywordLower);
              const fromMatch = mail.from.some(f => 
                (f.name?.toLowerCase() || '').includes(keywordLower) || 
                f.address.toLowerCase().includes(keywordLower)
              );
              const toMatch = mail.to.some(t => 
                (t.name?.toLowerCase() || '').includes(keywordLower) || 
                t.address.toLowerCase().includes(keywordLower)
              );
              
              // 如果需要在正文中搜索,可能需要额外获取邮件详情
              let bodyMatch = false;
              if (options.includeBody) {
                bodyMatch = (mail.textBody?.toLowerCase() || '').includes(keywordLower) ||
                           (mail.htmlBody?.toLowerCase() || '').includes(keywordLower);
              }
              
              return subjectMatch || fromMatch || toMatch || bodyMatch;
            });
            
            allResults.push(...filteredResults);
          } else {
            allResults.push(...folderResults);
          }
        } catch (error) {
          console.error(`搜索文件夹 ${folder} 时出错:`, error);
          // 继续搜索其他文件夹
        }
      }
      
      // 按日期降序排序(最新的邮件优先)
      allResults.sort((a, b) => b.date.getTime() - a.date.getTime());
      
      // 限制结果数量
      return allResults.slice(0, maxResults);
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shuakami/mcp-mail'

If you have feedback or need assistance with the MCP directory API, please join our Discord server