@atengk/mcp-server-email 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -558,10 +558,14 @@ var ImapService = class {
558
558
  const scanUids = sortedUids.slice(0, maxScanLimit);
559
559
  const matchedUids = [];
560
560
  if (scanUids.length > 0) {
561
- for await (const message of client.fetch(scanUids, {
562
- uid: true,
563
- bodyStructure: true
564
- })) {
561
+ for await (const message of client.fetch(
562
+ scanUids,
563
+ {
564
+ uid: true,
565
+ bodyStructure: true
566
+ },
567
+ { uid: true }
568
+ )) {
565
569
  const hasAttachments = Boolean(
566
570
  message.bodyStructure?.childNodes && message.bodyStructure.childNodes.length > 1
567
571
  );
@@ -578,15 +582,19 @@ var ImapService = class {
578
582
  }
579
583
  const items = [];
580
584
  if (selectedUids.length > 0) {
581
- for await (const message of client.fetch(selectedUids, {
582
- envelope: true,
583
- flags: true,
584
- internalDate: true,
585
- uid: true,
586
- bodyStructure: true,
587
- bodyParts: ["TEXT", "1"],
588
- source: { maxLength: 2048 }
589
- })) {
585
+ for await (const message of client.fetch(
586
+ selectedUids,
587
+ {
588
+ envelope: true,
589
+ flags: true,
590
+ internalDate: true,
591
+ uid: true,
592
+ bodyStructure: true,
593
+ bodyParts: ["TEXT", "1"],
594
+ source: { maxLength: 2048 }
595
+ },
596
+ { uid: true }
597
+ )) {
590
598
  const hasAttachments = Boolean(
591
599
  message.bodyStructure?.childNodes && message.bodyStructure.childNodes.length > 1
592
600
  );
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config/index.ts","../src/tools/index.ts","../src/services/imap.service.ts","../src/services/mailbox-resolver.ts","../src/services/attachment-sandbox.ts","../src/services/content-purifier.ts","../src/services/smtp.service.ts","../src/services/account-manager.ts","../src/services/reply.service.ts"],"sourcesContent":["/**\n * MCP Server Email 服务主入口\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport http from \"node:http\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { config } from \"./config/index.js\";\nimport { registerEmailTools } from \"./tools/index.js\";\n\n/**\n * 启动 MCP 邮件服务端\n */\nasync function main(): Promise<void> {\n // 1. 初始化 MCP 服务端实例\n const server = new McpServer({\n name: \"mcp-server-email\",\n version: \"1.0.1\",\n });\n\n // 2. 注册邮件交互工具\n registerEmailTools(server);\n\n // 3. 命令行参数解析优先级高于环境变量\n const args = process.argv.slice(2);\n let transportMode = config.MCP_TRANSPORT;\n let port = config.MCP_PORT;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--transport\" && args[i + 1]) {\n transportMode = args[i + 1] === \"sse\" ? \"sse\" : \"stdio\";\n i++;\n } else if (args[i] === \"--port\" && args[i + 1]) {\n port = parseInt(args[i + 1], 10) || 3000;\n i++;\n }\n }\n\n // 4. 根据模式启动通信监听\n if (transportMode === \"sse\") {\n const sessions = new Map<string, SSEServerTransport>();\n\n const httpServer = http.createServer(async (req, res) => {\n const url = new URL(req.url || \"/\", `http://${req.headers.host || \"localhost\"}`);\n\n // 允许跨域调用 (CORS)\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204).end();\n return;\n }\n\n if (url.pathname === \"/sse\") {\n const transport = new SSEServerTransport(\"/messages\", res);\n sessions.set(transport.sessionId, transport);\n\n res.on(\"close\", () => {\n sessions.delete(transport.sessionId);\n console.error(`[MCP Email Server] SSE 会话已断开: ${transport.sessionId}`);\n });\n\n await server.connect(transport);\n console.error(`[MCP Email Server] SSE 传输连接已建立: ${transport.sessionId}`);\n } else if (url.pathname === \"/messages\" && req.method === \"POST\") {\n const sessionId = url.searchParams.get(\"sessionId\");\n const transport = sessionId\n ? sessions.get(sessionId)\n : sessions.values().next().value || null;\n\n if (transport) {\n await transport.handlePostMessage(req, res);\n } else {\n res\n .writeHead(400, { \"Content-Type\": \"text/plain; charset=utf-8\" })\n .end(\"无效或未找到对应的 SSE 传输会话\");\n }\n } else if (url.pathname === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n status: \"ok\",\n activeSessions: sessions.size,\n timestamp: new Date().toISOString(),\n })\n );\n } else {\n res.writeHead(404).end(\"Not Found\");\n }\n });\n\n httpServer.listen(port, () => {\n console.error(`[MCP Email Server] SSE 模式正在监听端口: ${port}`);\n });\n } else {\n // 默认 Stdio 模式 (标准输入输出,供本地 Claude Desktop / Cursor 进程拉起)\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[MCP Email Server] Stdio 传输已就绪,正在监听标准输入输出\");\n }\n}\n\nmain().catch((err: unknown) => {\n console.error(\"[MCP Email Server 崩溃]\", err);\n process.exit(1);\n});\n","/**\n * 服务端环境变量与多账户画像配置解析\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport { z } from \"zod\";\nimport type { AccountProfile } from \"../types/index.js\";\n\n// 加载本地环境变量\ndotenv.config();\n\n/**\n * SMTP 单配置 Schema\n */\nconst smtpProfileSchema = z.object({\n host: z.string(),\n port: z\n .union([z.number(), z.string().transform((val) => parseInt(val, 10))])\n .default(465),\n secure: z\n .union([z.boolean(), z.string().transform((val) => val === \"true\" || val === \"1\")])\n .default(true),\n user: z.string(),\n pass: z.string(),\n from: z.string().optional(),\n});\n\n/**\n * IMAP 单配置 Schema\n */\nconst imapProfileSchema = z.object({\n host: z.string(),\n port: z\n .union([z.number(), z.string().transform((val) => parseInt(val, 10))])\n .default(993),\n secure: z\n .union([z.boolean(), z.string().transform((val) => val === \"true\" || val === \"1\")])\n .default(true),\n user: z.string(),\n pass: z.string(),\n});\n\n/**\n * 完整账户画像 Schema\n */\nconst accountProfileSchema = z.object({\n id: z.string(),\n name: z.string().optional(),\n email: z.string().optional(),\n smtp: smtpProfileSchema.optional(),\n imap: imapProfileSchema.optional(),\n});\n\n/**\n * 环境变量顶层 Schema 定义\n */\nconst envSchema = z.object({\n // SMTP 配置 (向下兼容单账户)\n MCP_SMTP_HOST: z.string().optional(),\n MCP_SMTP_PORT: z\n .string()\n .optional()\n .transform((val) => (val ? parseInt(val, 10) : 465)),\n MCP_SMTP_SECURE: z\n .string()\n .optional()\n .transform((val) => val === undefined || val === \"true\" || val === \"1\"),\n MCP_SMTP_USER: z.string().optional(),\n MCP_SMTP_PASS: z.string().optional(),\n MCP_SMTP_FROM: z.string().optional(),\n\n // IMAP 配置 (向下兼容单账户)\n MCP_IMAP_HOST: z.string().optional(),\n MCP_IMAP_PORT: z\n .string()\n .optional()\n .transform((val) => (val ? parseInt(val, 10) : 993)),\n MCP_IMAP_SECURE: z\n .string()\n .optional()\n .transform((val) => val === undefined || val === \"true\" || val === \"1\"),\n MCP_IMAP_USER: z.string().optional(),\n MCP_IMAP_PASS: z.string().optional(),\n\n // 多账户配置\n MCP_ACCOUNTS: z.string().optional(),\n MCP_ACCOUNTS_FILE: z.string().optional(),\n MCP_DEFAULT_ACCOUNT: z.string().optional(),\n\n // MCP 传输与服务配置\n MCP_TRANSPORT: z.enum([\"stdio\", \"sse\"]).default(\"stdio\"),\n MCP_PORT: z\n .string()\n .optional()\n .transform((val) => (val ? parseInt(val, 10) : 3000)),\n MCP_LOG_LEVEL: z.string().default(\"info\"),\n});\n\nexport type AppConfig = z.infer<typeof envSchema> & {\n accounts: AccountProfile[];\n defaultAccountId: string;\n};\n\n/**\n * 将 JSON 数据解析为账户画像列表\n *\n * @param raw JSON 反序列化后的原始数据\n * @returns 规范化的账户画像列表\n */\nfunction parseAccountsFromJson(raw: unknown): AccountProfile[] {\n if (Array.isArray(raw)) {\n return z.array(accountProfileSchema).parse(raw);\n }\n if (typeof raw === \"object\" && raw !== null) {\n const record = z.record(accountProfileSchema.omit({ id: true })).parse(raw);\n return Object.entries(record).map(([id, profile]) => ({\n ...profile,\n id,\n }));\n }\n throw new Error(\"无效的账户配置格式,必须为 JSON 数组或键值对象\");\n}\n\n/**\n * 从环境变量与配置文件中解析多账户画像列表\n *\n * @param env 环境变量键值字典,缺省为 process.env\n * @returns 解析得到的账户列表与默认账户 ID\n */\nexport function parseAccountProfiles(\n env: Record<string, string | undefined> = process.env\n): { accounts: AccountProfile[]; defaultAccountId: string } {\n let accounts: AccountProfile[] = [];\n\n // 1. 优先尝试从 MCP_ACCOUNTS_FILE 配置文件加载\n const accountsFile = env.MCP_ACCOUNTS_FILE;\n if (accountsFile) {\n try {\n const resolvedPath = path.isAbsolute(accountsFile)\n ? accountsFile\n : path.resolve(process.cwd(), accountsFile);\n if (fs.existsSync(resolvedPath)) {\n const fileContent = fs.readFileSync(resolvedPath, \"utf-8\");\n accounts = parseAccountsFromJson(JSON.parse(fileContent));\n } else {\n console.error(`[配置警告] MCP_ACCOUNTS_FILE 指定的文件不存在: ${resolvedPath}`);\n }\n } catch (err: unknown) {\n console.error(\n \"[配置错误] 解析 MCP_ACCOUNTS_FILE 失败:\",\n err instanceof Error ? err.message : String(err)\n );\n }\n }\n\n // 2. 尝试从 MCP_ACCOUNTS 环境变量(JSON 字符串)解析\n const accountsJson = env.MCP_ACCOUNTS;\n if (accountsJson && accounts.length === 0) {\n try {\n accounts = parseAccountsFromJson(JSON.parse(accountsJson));\n } catch (err: unknown) {\n console.error(\n \"[配置错误] 解析 MCP_ACCOUNTS JSON 失败:\",\n err instanceof Error ? err.message : String(err)\n );\n }\n }\n\n // 3. 兼容单账户环境变量平滑回退 (MCP_SMTP_* / MCP_IMAP_*)\n if (accounts.length === 0) {\n const hasSmtp = Boolean(env.MCP_SMTP_HOST && env.MCP_SMTP_USER && env.MCP_SMTP_PASS);\n const hasImap = Boolean(env.MCP_IMAP_HOST && env.MCP_IMAP_USER && env.MCP_IMAP_PASS);\n\n if (hasSmtp || hasImap) {\n const defaultAccount: AccountProfile = {\n id: \"default\",\n name: \"默认邮箱账户\",\n email: env.MCP_SMTP_USER || env.MCP_IMAP_USER,\n };\n\n if (hasSmtp) {\n defaultAccount.smtp = {\n host: env.MCP_SMTP_HOST!,\n port: env.MCP_SMTP_PORT ? parseInt(env.MCP_SMTP_PORT, 10) : 465,\n secure:\n env.MCP_SMTP_SECURE === undefined ||\n env.MCP_SMTP_SECURE === \"true\" ||\n env.MCP_SMTP_SECURE === \"1\",\n user: env.MCP_SMTP_USER!,\n pass: env.MCP_SMTP_PASS!,\n from: env.MCP_SMTP_FROM,\n };\n }\n\n if (hasImap) {\n defaultAccount.imap = {\n host: env.MCP_IMAP_HOST!,\n port: env.MCP_IMAP_PORT ? parseInt(env.MCP_IMAP_PORT, 10) : 993,\n secure:\n env.MCP_IMAP_SECURE === undefined ||\n env.MCP_IMAP_SECURE === \"true\" ||\n env.MCP_IMAP_SECURE === \"1\",\n user: env.MCP_IMAP_USER!,\n pass: env.MCP_IMAP_PASS!,\n };\n }\n\n accounts.push(defaultAccount);\n }\n }\n\n // 4. 解析默认账户 ID\n let defaultAccountId = env.MCP_DEFAULT_ACCOUNT || \"\";\n if (!defaultAccountId || !accounts.some((a) => a.id === defaultAccountId)) {\n const defaultAcc = accounts.find((a) => a.id === \"default\");\n defaultAccountId = defaultAcc ? defaultAcc.id : accounts[0]?.id || \"default\";\n }\n\n return { accounts, defaultAccountId };\n}\n\n/**\n * 解析并获取已校验的环境变量与多账户配置\n *\n * @param env 环境变量键值字典,缺省为 process.env\n * @returns 结构化配置对象\n */\nexport function loadConfig(env: Record<string, string | undefined> = process.env): AppConfig {\n const result = envSchema.safeParse(env);\n if (!result.success) {\n console.error(\"[配置错误] 环境变量校验失败:\", result.error.format());\n throw new Error(\"环境变量格式无效,请检查 .env 配置\");\n }\n\n const { accounts, defaultAccountId } = parseAccountProfiles(env);\n\n return {\n ...result.data,\n accounts,\n defaultAccountId,\n };\n}\n\nexport const config = loadConfig();\n","/**\n * MCP 工具定义与请求分发注册\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { accountManager } from \"../services/account-manager.js\";\nimport { replyEmail } from \"../services/reply.service.js\";\n\n/**\n * 注册所有邮件相关的 MCP 工具到服务端实例\n *\n * @param server McpServer 实例\n */\nexport function registerEmailTools(server: McpServer): void {\n // 1. 列出可用邮箱账户画像(凭据脱敏)\n server.tool(\n \"list_accounts\",\n \"列出所有已配置的邮箱账户画像列表(凭据安全脱敏,隐藏密码),包含账户标识、邮箱地址、运行模式(full/send_only/receive_only)、收发能力特性与默认账户标记\",\n {},\n async () => {\n try {\n const accounts = accountManager.listAccounts();\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(accounts, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取账户列表失败: ${message}` }],\n };\n }\n }\n );\n\n // 2. 连通性自检与凭据体检工具\n server.tool(\n \"verify_connection\",\n \"验证指定或默认邮箱账户的网络连通性与认证凭据(支持全功能或纯发信模式,自动识别 SMTP 与 IMAP),返回网络握手与身份认证综合体检诊断报告\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时体检默认账户\"),\n },\n async (args) => {\n try {\n const report = await accountManager.verifyConnection(args.account);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(report, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `验证账户连接失败: ${message}` }],\n };\n }\n }\n );\n\n // 3. 发送邮件工具\n server.tool(\n \"send_email\",\n \"发送电子邮件,支持纯文本、HTML 正文以及文件附件\",\n {\n account: z.string().optional().describe(\"发信邮箱账户画像标识,缺省时使用默认账户\"),\n to: z.union([z.string(), z.array(z.string())]).describe(\"收件人邮箱地址,单个或数组\"),\n subject: z.string().describe(\"邮件主题\"),\n text: z.string().optional().describe(\"纯文本正文内容\"),\n html: z.string().optional().describe(\"HTML 格式正文内容\"),\n cc: z.union([z.string(), z.array(z.string())]).optional().describe(\"抄送邮箱地址\"),\n bcc: z.union([z.string(), z.array(z.string())]).optional().describe(\"密送邮箱地址\"),\n attachments: z\n .array(\n z.object({\n filename: z.string().describe(\"附件文件名\"),\n path: z.string().optional().describe(\"本地文件绝对路径\"),\n content: z.string().optional().describe(\"附件文本内容或 Base64 编码字符串\"),\n contentType: z.string().optional().describe(\"MIME 类型\"),\n })\n )\n .optional()\n .describe(\"附件列表\"),\n },\n async (args) => {\n try {\n const smtpService = accountManager.getSmtpService(args.account);\n const result = await smtpService.sendEmail({\n to: args.to,\n subject: args.subject,\n text: args.text,\n html: args.html,\n cc: args.cc,\n bcc: args.bcc,\n attachments: args.attachments,\n });\n\n return {\n content: [\n {\n type: \"text\",\n text: `邮件发送成功!MessageID: ${result.messageId},已投递至: ${result.accepted.join(\", \")}`,\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `发送邮件失败: ${message}` }],\n };\n }\n }\n );\n\n // 4. 会话回复工具\n server.tool(\n \"reply_email\",\n \"回复指定邮件,自动保持原生会话折叠树(自动注入 In-Reply-To、References 邮件头,添加 Re: 主题前缀,支持一键 replyAll 保留原抄送人)\",\n {\n account: z.string().optional().describe(\"发送回复的邮箱账户画像标识,缺省时使用默认账户\"),\n originalUid: z.number().describe(\"被回复原邮件的唯一 UID 标识符\"),\n mailbox: z.string().optional().default(\"INBOX\").describe(\"原邮件所在邮箱文件夹名称,默认为 INBOX\"),\n text: z.string().optional().describe(\"回复的纯文本正文内容\"),\n html: z.string().optional().describe(\"回复的 HTML 格式正文内容\"),\n replyAll: z.boolean().optional().default(false).describe(\"是否全员回复(抄送除自身外的原邮件收件人与抄送人)\"),\n attachments: z\n .array(\n z.object({\n filename: z.string().describe(\"附件文件名\"),\n path: z.string().optional().describe(\"本地文件绝对路径\"),\n content: z.string().optional().describe(\"附件文本内容或 Base64 编码字符串\"),\n contentType: z.string().optional().describe(\"MIME 类型\"),\n })\n )\n .optional()\n .describe(\"附件列表\"),\n },\n async (args) => {\n try {\n const account = accountManager.getAccount(args.account);\n const imapService = accountManager.getImapService(args.account);\n const smtpService = accountManager.getSmtpService(args.account);\n\n const result = await replyEmail(\n {\n originalUid: args.originalUid,\n mailbox: args.mailbox,\n text: args.text,\n html: args.html,\n replyAll: args.replyAll,\n attachments: args.attachments,\n },\n account,\n imapService,\n smtpService\n );\n\n return {\n content: [\n {\n type: \"text\",\n text: `邮件回复成功!MessageID: ${result.messageId},已回复至: ${result.to}${result.cc ? ` (抄送: ${result.cc.join(\", \")})` : \"\"},主题: ${result.subject}`,\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `回复邮件失败: ${message}` }],\n };\n }\n }\n );\n\n // 5. 保存至草稿箱工具\n server.tool(\n \"create_draft\",\n \"将拟定邮件存入邮箱草稿箱(Drafts),供人工在邮箱客户端中最终审阅确认后发出\",\n {\n account: z.string().optional().describe(\"草稿所属邮箱账户画像标识,缺省时使用默认账户\"),\n to: z.union([z.string(), z.array(z.string())]).optional().describe(\"收件人邮箱地址,单个或数组\"),\n subject: z.string().optional().default(\"(无主题)\").describe(\"邮件主题\"),\n text: z.string().optional().describe(\"纯文本正文内容\"),\n html: z.string().optional().describe(\"HTML 格式正文内容\"),\n cc: z.union([z.string(), z.array(z.string())]).optional().describe(\"抄送邮箱地址\"),\n bcc: z.union([z.string(), z.array(z.string())]).optional().describe(\"密送邮箱地址\"),\n attachments: z\n .array(\n z.object({\n filename: z.string().describe(\"附件文件名\"),\n path: z.string().optional().describe(\"本地文件绝对路径\"),\n content: z.string().optional().describe(\"附件文本内容或 Base64 编码字符串\"),\n contentType: z.string().optional().describe(\"MIME 类型\"),\n })\n )\n .optional()\n .describe(\"附件列表\"),\n },\n async (args) => {\n try {\n const account = accountManager.getAccount(args.account);\n const imapService = accountManager.getImapService(args.account);\n const from =\n account.smtp?.from ||\n account.smtp?.user ||\n account.email ||\n \"user@example.com\";\n\n const result = await imapService.createDraft(\n {\n to: args.to || \"\",\n subject: args.subject || \"(无主题)\",\n text: args.text,\n html: args.html,\n cc: args.cc,\n bcc: args.bcc,\n attachments: args.attachments,\n },\n from\n );\n\n return {\n content: [\n {\n type: \"text\",\n text: `草稿已成功保存至 [${result.mailbox}]!主题: ${args.subject || \"(无主题)\"}`,\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `保存草稿箱失败: ${message}` }],\n };\n }\n }\n );\n\n // 6. 极速状态看板工具\n server.tool(\n \"get_mailbox_status\",\n \"极速获取指定或全部邮箱文件夹的状态看板(包含总邮件数、未读邮件数与最近邮件数),毫秒级响应\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n mailbox: z\n .string()\n .optional()\n .describe(\n \"目标邮箱文件夹别名或物理路径(如 inbox, drafts, trash 或 INBOX),缺省时统计全部可用文件夹\"\n ),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const report = await imapService.getMailboxStatus(args.mailbox);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(report, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取邮箱状态失败: ${message}` }],\n };\n }\n }\n );\n\n // 7. 检索邮件列表工具 (多维复合检索与分页)\n server.tool(\n \"search_emails\",\n \"在邮箱中按多维条件检索邮件,返回包含 150 字符 Preview 纯文本摘要的分页列表\",\n {\n account: z.string().optional().describe(\"收信邮箱账户画像标识,缺省时使用默认账户\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"邮箱文件夹名称或别名(如 inbox, drafts, trash),默认为 INBOX\"),\n query: z.string().optional().describe(\"全文检索关键字(匹配发件人、主题或正文)\"),\n from: z.string().optional().describe(\"按发件人地址或关键字筛选\"),\n to: z.string().optional().describe(\"按收件人地址或关键字筛选\"),\n subject: z.string().optional().describe(\"按邮件主题关键字筛选\"),\n unseenOnly: z.boolean().optional().default(false).describe(\"是否仅查询未读邮件\"),\n flaggedOnly: z.boolean().optional().default(false).describe(\"是否仅查询星标/置顶邮件\"),\n hasAttachment: z.boolean().optional().describe(\"是否必须包含附件\"),\n since: z.string().optional().describe(\"起始日期筛选,格式如 YYYY-MM-DD\"),\n before: z.string().optional().describe(\"截止日期筛选,格式如 YYYY-MM-DD\"),\n page: z.number().optional().default(1).describe(\"当前页码,从 1 开始,默认 1\"),\n limit: z.number().optional().default(10).describe(\"每页拉取条数,默认 10\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.searchEmails({\n mailbox: args.mailbox,\n query: args.query,\n from: args.from,\n to: args.to,\n subject: args.subject,\n unseenOnly: args.unseenOnly,\n flaggedOnly: args.flaggedOnly,\n hasAttachment: args.hasAttachment,\n since: args.since,\n before: args.before,\n page: args.page,\n limit: args.limit,\n });\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `检索邮件列表失败: ${message}` }],\n };\n }\n }\n );\n\n\n // 7. 获取邮件正文及附件详情工具\n server.tool(\n \"get_email_detail\",\n \"根据邮件全局 UID 获取单封邮件的完整正文内容与附件清单\",\n {\n account: z.string().optional().describe(\"收信邮箱账户画像标识,缺省时使用默认账户\"),\n uid: z.number().describe(\"邮件的唯一 UID 标识符\"),\n mailbox: z.string().optional().default(\"INBOX\").describe(\"邮箱文件夹名称,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const detail = await imapService.getEmailDetail(args.uid, args.mailbox);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(detail, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取邮件详情失败: ${message}` }],\n };\n }\n }\n );\n\n // 8. 列出全部邮箱目录工具\n server.tool(\n \"list_mailboxes\",\n \"获取当前邮箱服务的所有可用文件夹/目录列表(如 INBOX, Sent, Trash 等)\",\n {\n account: z.string().optional().describe(\"收信邮箱账户画像标识,缺省时使用默认账户\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const mailboxes = await imapService.listMailboxes();\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(mailboxes, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取邮箱目录失败: ${message}` }],\n };\n }\n }\n );\n\n // 9. 下载附件至本地受管沙箱工具\n server.tool(\n \"download_attachment\",\n \"将指定邮件的附件按需提取并安全保存至本地受管沙箱目录,返回物理绝对路径与 file:/// 直达 URI\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uid: z.number().describe(\"邮件的唯一 UID 标识符\"),\n attachmentId: z\n .string()\n .describe(\"待下载附件的标识 ID(对应 get_email_detail 返回的附件 id,如 '0')或附件文件名\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"原邮件所在邮箱文件夹名称或别名,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.downloadAttachment(\n args.uid,\n args.attachmentId,\n args.mailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `下载附件失败: ${message}` }],\n };\n }\n }\n );\n\n // 10. 标记邮件已读/未读工具\n server.tool(\n \"mark_email_read\",\n \"对单封或批量邮件设置已读或未读标记(\\\\Seen),协助完成待办邮件分诊流转\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uids: z\n .union([z.number(), z.array(z.number())])\n .describe(\"单封邮件 UID(数字)或批量邮件 UID 数组(如 [101, 102])\"),\n read: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"是否标记为已读(true 为已读,false 为未读),默认为 true\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"目标邮箱文件夹别名或物理路径,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.markEmailRead(\n args.uids,\n args.read,\n args.mailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `标记已读状态失败: ${message}` }],\n };\n }\n }\n );\n\n // 11. 邮件星标/置顶标记工具\n server.tool(\n \"flag_email\",\n \"对单封或批量邮件设置或取消重要星标标记(\\\\Flagged),用于重点关注或待办标记\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uids: z\n .union([z.number(), z.array(z.number())])\n .describe(\"单封邮件 UID(数字)或批量邮件 UID 数组(如 [101, 102])\"),\n flagged: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"是否设置星标(true 为星标置顶,false 为取消星标),默认为 true\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"目标邮箱文件夹别名或物理路径,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.flagEmail(\n args.uids,\n args.flagged,\n args.mailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `设置星标状态失败: ${message}` }],\n };\n }\n }\n );\n\n // 12. 邮件跨文件夹移动与防灾软删除工具\n server.tool(\n \"move_email\",\n \"将单封或批量邮件移动至目标文件夹(如归档至 archive);彻底禁用物理硬删除,删除邮件请指定 targetMailbox 为 trash 进行安全软删除\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uids: z\n .union([z.number(), z.array(z.number())])\n .describe(\"单封邮件 UID(数字)或批量邮件 UID 数组(如 [101, 102])\"),\n targetMailbox: z\n .string()\n .describe(\"目标邮箱文件夹别名或物理路径(如 trash 进行软删除,或 archive 归档)\"),\n sourceMailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"源邮箱文件夹别名或物理路径,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.moveEmail(\n args.uids,\n args.targetMailbox,\n args.sourceMailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `移动邮件失败: ${message}` }],\n };\n }\n }\n );\n}\n","/**\n * IMAP 邮件查收与检索服务\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport { ImapFlow } from \"imapflow\";\nimport { simpleParser } from \"mailparser\";\nimport { config } from \"../config/index.js\";\nimport type {\n DownloadAttachmentResult,\n EmailAttachmentMetadata,\n EmailDetail,\n EmailSummary,\n FlagEmailResult,\n ImapConfig,\n MailboxStatus,\n MailboxStatusReport,\n MarkEmailReadResult,\n MoveEmailResult,\n SearchEmailFilter,\n SearchEmailsResult,\n SendEmailOptions,\n} from \"../types/index.js\";\nimport {\n buildRawMimeMessage,\n extractPreviewSnippet,\n parseBodyFromRawOrParts,\n resolveSpecialMailbox,\n} from \"./mailbox-resolver.js\";\nimport { purifyEmailBody } from \"./content-purifier.js\";\nimport { saveAttachmentToSandbox } from \"./attachment-sandbox.js\";\n\n\n\n\n/**\n * IMAP 邮件存储交互服务\n */\nexport class ImapService {\n constructor(private readonly imapConfig?: ImapConfig) {}\n\n /**\n * 创建新的 IMAP 客户端连接\n *\n * @returns 初始化的 ImapFlow 客户端实例\n * @throws Error 当未配置 IMAP 主机或账号时\n */\n private createClient(): ImapFlow {\n const host = this.imapConfig?.host || config.MCP_IMAP_HOST;\n const port = this.imapConfig?.port ?? config.MCP_IMAP_PORT;\n const secure = this.imapConfig?.secure ?? config.MCP_IMAP_SECURE;\n const user = this.imapConfig?.user || config.MCP_IMAP_USER;\n const pass = this.imapConfig?.pass || config.MCP_IMAP_PASS;\n\n if (!host || !user || !pass) {\n throw new Error(\n \"IMAP 配置不完整:请确保已配置 MCP_IMAP_HOST、MCP_IMAP_USER 和 MCP_IMAP_PASS 环境变量\"\n );\n }\n\n return new ImapFlow({\n host,\n port,\n secure,\n auth: {\n user,\n pass,\n },\n logger: false, // 禁用内部控制台输出,保护 MCP Stdio 通信通道\n });\n }\n\n /**\n * 获取远程邮箱目录列表\n *\n * @returns 邮箱目录路径列表\n */\n async listMailboxes(): Promise<string[]> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n return mailboxes.map((item) => item.path);\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 检索符合条件的邮件摘要列表\n *\n * @param filter 检索与过滤条件\n * @returns 分页检索结果与条目摘要\n */\n async searchEmails(filter: SearchEmailFilter): Promise<SearchEmailsResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n // 1. 获取物理邮箱列表并解析逻辑别名\n const allMailboxes = await client.list();\n const targetMailbox = resolveSpecialMailbox(filter.mailbox || \"INBOX\", allMailboxes);\n\n const lock = await client.getMailboxLock(targetMailbox);\n try {\n // 2. 组装 IMAP 查询条件字典\n const query: Record<string, unknown> = {};\n\n if (filter.query) {\n query.body = filter.query;\n }\n if (filter.unseenOnly) {\n query.seen = false;\n }\n if (filter.flaggedOnly) {\n query.flagged = true;\n }\n if (filter.from) {\n query.from = filter.from;\n }\n if (filter.to) {\n query.to = filter.to;\n }\n if (filter.subject) {\n query.subject = filter.subject;\n }\n if (filter.since) {\n query.since = new Date(filter.since);\n }\n if (filter.before) {\n query.before = new Date(filter.before);\n }\n\n const searchCriteria = Object.keys(query).length > 0 ? query : { all: true };\n const searchResult = await client.search(searchCriteria, { uid: true });\n const uids: number[] = Array.isArray(searchResult) ? searchResult : [];\n\n const total = uids.length;\n const page = filter.page && filter.page > 0 ? filter.page : 1;\n const limit = filter.limit && filter.limit > 0 ? filter.limit : 10;\n\n if (total === 0) {\n return {\n items: [],\n total: 0,\n page,\n limit,\n hasMore: false,\n };\n }\n\n // 3. 计算分页切片与拉取条目\n const sortedUids = [...uids].reverse();\n let selectedUids: number[] = [];\n let effectiveTotal = total;\n let hasMore = false;\n\n if (filter.hasAttachment === undefined) {\n // 常规无附件过滤场景:直接高效分页切片\n const startIndex = (page - 1) * limit;\n selectedUids = sortedUids.slice(startIndex, startIndex + limit);\n hasMore = startIndex + limit < total;\n } else {\n // 带有附件过滤场景:窗口探测回填(最大探测深度 100 封,消除分页稀疏断层)\n const maxScanLimit = Math.min(sortedUids.length, 100);\n const scanUids = sortedUids.slice(0, maxScanLimit);\n const matchedUids: number[] = [];\n\n if (scanUids.length > 0) {\n for await (const message of client.fetch(scanUids, {\n uid: true,\n bodyStructure: true,\n })) {\n const hasAttachments = Boolean(\n message.bodyStructure?.childNodes &&\n message.bodyStructure.childNodes.length > 1\n );\n if (hasAttachments === filter.hasAttachment) {\n matchedUids.push(message.uid);\n }\n }\n }\n\n // 保持逆序排布(最新邮件优先)\n matchedUids.sort((a, b) => b - a);\n effectiveTotal = matchedUids.length;\n const startIndex = (page - 1) * limit;\n selectedUids = matchedUids.slice(startIndex, startIndex + limit);\n hasMore = startIndex + limit < matchedUids.length;\n }\n\n const items: EmailSummary[] = [];\n\n if (selectedUids.length > 0) {\n for await (const message of client.fetch(selectedUids, {\n envelope: true,\n flags: true,\n internalDate: true,\n uid: true,\n bodyStructure: true,\n bodyParts: [\"TEXT\", \"1\"],\n source: { maxLength: 2048 },\n })) {\n const hasAttachments = Boolean(\n message.bodyStructure?.childNodes &&\n message.bodyStructure.childNodes.length > 1\n );\n\n const fromAddr = message.envelope?.from?.[0]\n ? `${message.envelope.from[0].name || \"\"} <${message.envelope.from[0].address || \"\"}>`.trim()\n : \"未知发件人\";\n\n // 提取正文并清洗为 150 字符 Preview 摘要\n const rawBody = parseBodyFromRawOrParts(message.bodyParts, message.source);\n const preview = extractPreviewSnippet(rawBody, 150);\n\n items.push({\n uid: message.uid,\n seq: message.seq,\n from: fromAddr,\n subject: message.envelope?.subject || \"(无主题)\",\n date: message.envelope?.date?.toISOString() || new Date().toISOString(),\n unseen: !message.flags?.has(\"\\\\Seen\"),\n hasAttachments,\n preview,\n });\n }\n\n // 保证返回项顺序与 selectedUids 顺序一致\n items.sort((a, b) => b.uid - a.uid);\n }\n\n return {\n items,\n total: effectiveTotal,\n page,\n limit,\n hasMore,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n\n }\n\n /**\n * 根据 UID 获取邮件正文及附件明细(包含 Markdown 提纯与附件元数据清单)\n *\n * @param uid 邮件唯一标识符\n * @param mailbox 所处邮箱文件夹或别名,默认 INBOX\n * @returns 邮件详情数据\n */\n async getEmailDetail(uid: number, mailbox = \"INBOX\"): Promise<EmailDetail> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const targetMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(targetMailbox);\n try {\n const download = await client.download(String(uid), undefined, { uid: true });\n if (!download || !download.content) {\n throw new Error(`未找到 UID 为 ${uid} 的邮件内容`);\n }\n\n const parsed = await simpleParser(download.content);\n\n const toList: string[] = [];\n if (parsed.to) {\n if (Array.isArray(parsed.to)) {\n parsed.to.forEach((addr) => toList.push(addr.text));\n } else {\n toList.push(parsed.to.text);\n }\n }\n\n const ccList: string[] = [];\n if (parsed.cc) {\n if (Array.isArray(parsed.cc)) {\n parsed.cc.forEach((addr) => ccList.push(addr.text));\n } else {\n ccList.push(parsed.cc.text);\n }\n }\n\n // 仅提取轻量元数据清单,严禁嵌入大体积 Base64,保护 Token 经济性\n const attachments: EmailAttachmentMetadata[] = (parsed.attachments || []).map((att, idx) => ({\n id: String(idx),\n filename: att.filename || `attachment-${idx}`,\n contentType: att.contentType || \"application/octet-stream\",\n size: att.size || (att.content ? att.content.length : 0),\n }));\n\n const fromAddress = parsed.from?.value?.[0]?.address || undefined;\n let references: string[] | undefined;\n if (parsed.references) {\n references = Array.isArray(parsed.references)\n ? parsed.references\n : [parsed.references];\n }\n\n // 清洗提纯 HTML 为轻量 Markdown,执行 30KB 安全截断\n const purified = purifyEmailBody(\n parsed.text,\n typeof parsed.html === \"string\" ? parsed.html : undefined\n );\n\n return {\n uid,\n from: parsed.from?.text || \"未知发件人\",\n fromAddress,\n to: toList,\n cc: ccList.length > 0 ? ccList : undefined,\n subject: parsed.subject || \"(无主题)\",\n date: parsed.date ? parsed.date.toISOString() : new Date().toISOString(),\n text: parsed.text,\n html: typeof parsed.html === \"string\" ? parsed.html : undefined,\n bodyMarkdown: purified.content,\n truncated: purified.truncated,\n messageId: parsed.messageId,\n inReplyTo: parsed.inReplyTo,\n references,\n attachments,\n };\n\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 从指定邮件中提取附件并下载保存至受管本地沙箱\n *\n * @param uid 邮件唯一标识符\n * @param attachmentIdentifier 附件唯一标识(ID 序号或文件名)\n * @param mailbox 所在邮箱文件夹,默认 INBOX\n * @returns 下载落盘结果\n * @throws Error 当未找到邮件或目标附件时\n */\n async downloadAttachment(\n uid: number,\n attachmentIdentifier: string,\n mailbox = \"INBOX\"\n ): Promise<DownloadAttachmentResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const targetMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(targetMailbox);\n try {\n const download = await client.download(String(uid), undefined, { uid: true });\n if (!download || !download.content) {\n throw new Error(`未找到 UID 为 ${uid} 的邮件内容`);\n }\n\n const parsed = await simpleParser(download.content);\n const attachments = parsed.attachments || [];\n\n // 优先通过数字索引匹配,其次匹配文件名\n const targetIndex = attachments.findIndex(\n (att, idx) =>\n String(idx) === String(attachmentIdentifier) ||\n att.filename === attachmentIdentifier\n );\n\n if (targetIndex === -1) {\n throw new Error(\n `未在邮件 (UID: ${uid}) 中找到标识为 \"${attachmentIdentifier}\" 的附件`\n );\n }\n\n const targetAttachment = attachments[targetIndex];\n if (!targetAttachment.content) {\n throw new Error(\n `附件 \"${targetAttachment.filename || attachmentIdentifier}\" 内容为空或无法提取`\n );\n }\n\n const rawFileName = targetAttachment.filename || `attachment-${targetIndex}`;\n const saved = await saveAttachmentToSandbox(rawFileName, targetAttachment.content, undefined, uid);\n\n return {\n attachmentId: String(targetIndex),\n filename: saved.filename,\n contentType: targetAttachment.contentType || \"application/octet-stream\",\n size: saved.size,\n filePath: saved.filePath,\n fileUrl: saved.fileUrl,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 验证 IMAP 服务的网络握手与身份认证\n *\n * @returns 是否连接成功\n */\n async verifyConnection(): Promise<boolean> {\n const client = this.createClient();\n try {\n await client.connect();\n return true;\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 将邮件载荷组装为 RFC 822 MIME 数据并存入草稿箱\n *\n * @param options 邮件选项载荷\n * @param from 发件人地址\n * @returns 存储结果,包含物理草稿箱路径\n */\n async createDraft(\n options: SendEmailOptions,\n from: string\n ): Promise<{ success: boolean; mailbox: string }> {\n const client = this.createClient();\n await client.connect();\n\n try {\n // 1. 获取邮箱列表并解析物理草稿箱路径\n const mailboxes = await client.list();\n const draftsPath = resolveSpecialMailbox(\"drafts\", mailboxes);\n\n // 2. 组装标准 RFC MIME Buffer\n const rawMime = await buildRawMimeMessage(options, from);\n\n // 3. 追加至草稿箱,打上 \\Draft 与 \\Seen 标记\n await client.append(draftsPath, rawMime, [\"\\\\Draft\", \"\\\\Seen\"]);\n\n return {\n success: true,\n mailbox: draftsPath,\n };\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 极速获取邮箱文件夹状态与未读统计看板\n *\n * @param mailboxAlias 可选指定文件夹别名或物理路径,缺省时查询全部可用文件夹\n * @returns 邮箱状态看板概览报告\n */\n async getMailboxStatus(mailboxAlias?: string): Promise<MailboxStatusReport> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const allMailboxes = await client.list();\n\n // 1. 如果指定了具体文件夹(如 \"INBOX\", \"drafts\" 等),解析别名并只查该文件夹\n if (mailboxAlias && mailboxAlias.toUpperCase() !== \"ALL\") {\n const resolvedPath = resolveSpecialMailbox(mailboxAlias, allMailboxes);\n const status = await client.status(resolvedPath, {\n messages: true,\n unseen: true,\n recent: true,\n });\n\n const item: MailboxStatus = {\n mailbox: resolvedPath,\n total: status.messages || 0,\n unseen: status.unseen || 0,\n recent: status.recent || 0,\n };\n\n return {\n mailboxes: [item],\n totalUnseen: item.unseen,\n totalMessages: item.total,\n };\n }\n\n // 2. 缺省或 ALL 时,并发管道化统计所有物理邮箱状态\n const statusPromises = allMailboxes.map(async (box) => {\n try {\n const status = await client.status(box.path, {\n messages: true,\n unseen: true,\n recent: true,\n });\n\n return {\n mailbox: box.path,\n total: status.messages || 0,\n unseen: status.unseen || 0,\n recent: status.recent || 0,\n };\n } catch {\n // 部分特殊目录可能不支持 STATUS,静默降级为 0\n return {\n mailbox: box.path,\n total: 0,\n unseen: 0,\n recent: 0,\n };\n }\n });\n\n const items = await Promise.all(statusPromises);\n let totalUnseen = 0;\n let totalMessages = 0;\n\n for (const item of items) {\n totalUnseen += item.unseen;\n totalMessages += item.total;\n }\n\n return {\n mailboxes: items,\n totalUnseen,\n totalMessages,\n };\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 将邮件 UID 或 UID 列表格式化为 IMAP SequenceSet 字符串并执行有效性校验\n *\n * @param uids 单个 UID 或 UID 数组\n * @returns 规整后的 IMAP 查询范围字符串与计数\n * @throws Error 当未提供任何有效 UID 时\n */\n private formatUidRange(uids: number | number[]): { range: string; count: number } {\n const list = Array.isArray(uids) ? uids : [uids];\n const valid = list.filter((u) => typeof u === \"number\" && !isNaN(u) && u > 0);\n if (valid.length === 0) {\n throw new Error(\"请提供至少一个有效的邮件 UID 标识符\");\n }\n const sorted = Array.from(new Set(valid)).sort((a, b) => a - b);\n return {\n range: sorted.join(\",\"),\n count: sorted.length,\n };\n }\n\n /**\n * 修改邮件的已读/未读状态标记 (\\Seen)\n *\n * @param uids 单个邮件 UID 或 UID 列表\n * @param read 是否标记为已读(true 为已读,false 为未读,默认 true)\n * @param mailbox 所在邮箱文件夹别名或物理路径,默认 INBOX\n * @returns 状态流转操作结果\n */\n async markEmailRead(\n uids: number | number[],\n read = true,\n mailbox = \"INBOX\"\n ): Promise<MarkEmailReadResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const resolvedMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(resolvedMailbox);\n try {\n const { range, count } = this.formatUidRange(uids);\n if (read) {\n await client.messageFlagsAdd(range, [\"\\\\Seen\"], { uid: true });\n } else {\n await client.messageFlagsRemove(range, [\"\\\\Seen\"], { uid: true });\n }\n\n return {\n success: true,\n count,\n read,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 修改邮件的星标/置顶标记 (\\Flagged)\n *\n * @param uids 单个邮件 UID 或 UID 列表\n * @param flagged 是否设置星标(true 为星标,false 为取消星标,默认 true)\n * @param mailbox 所在邮箱文件夹别名或物理路径,默认 INBOX\n * @returns 星标设置操作结果\n */\n async flagEmail(\n uids: number | number[],\n flagged = true,\n mailbox = \"INBOX\"\n ): Promise<FlagEmailResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const resolvedMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(resolvedMailbox);\n try {\n const { range, count } = this.formatUidRange(uids);\n if (flagged) {\n await client.messageFlagsAdd(range, [\"\\\\Flagged\"], { uid: true });\n } else {\n await client.messageFlagsRemove(range, [\"\\\\Flagged\"], { uid: true });\n }\n\n return {\n success: true,\n count,\n flagged,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 将邮件跨文件夹移动或转移至回收站进行安全软删除(彻底杜绝物理硬删除 EXPUNGE)\n *\n * @param uids 单个邮件 UID 或 UID 列表\n * @param targetMailbox 目标邮箱文件夹别名或物理路径(如 trash, archive, INBOX)\n * @param sourceMailbox 源邮箱文件夹别名或物理路径,默认 INBOX\n * @returns 移动结果,包含实际物理源路径与目标路径\n */\n async moveEmail(\n uids: number | number[],\n targetMailbox: string,\n sourceMailbox = \"INBOX\"\n ): Promise<MoveEmailResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const resolvedSource = resolveSpecialMailbox(sourceMailbox, mailboxes);\n const resolvedTarget = resolveSpecialMailbox(targetMailbox, mailboxes);\n\n const lock = await client.getMailboxLock(resolvedSource);\n try {\n const { range, count } = this.formatUidRange(uids);\n await client.messageMove(range, resolvedTarget, { uid: true });\n\n return {\n success: true,\n count,\n sourceMailbox: resolvedSource,\n targetMailbox: resolvedTarget,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n}\n\nexport const imapService = new ImapService();\n\n\n","/**\n * 特殊用途邮箱目录别名解析与 MIME 载荷构造\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport nodemailer from \"nodemailer\";\nimport type { SendEmailOptions } from \"../types/index.js\";\nimport { validateOutboundAttachmentPath } from \"./attachment-sandbox.js\";\n\n/**\n * 远程邮箱元数据项\n */\nexport interface MailboxItem {\n /** 物理邮箱路径,如 INBOX, [Gmail]/Drafts, 草稿箱 */\n path: string;\n /** 邮箱显示名称 */\n name?: string;\n /** RFC 6154 Special-Use 标志,如 \\Drafts, \\Trash, \\Sent, \\Inbox */\n specialUse?: string;\n}\n\n/**\n * 将逻辑别名(如 drafts, trash, sent, inbox)映射为当前邮箱服务商的物理路径\n *\n * @param logicalAlias 逻辑别名或自定义目录名\n * @param availableMailboxes 服务端返回的物理邮箱列表\n * @returns 解析后的物理邮箱路径\n */\nexport function resolveSpecialMailbox(\n logicalAlias: string,\n availableMailboxes: Array<MailboxItem | string> = []\n): string {\n const normalized = (logicalAlias || \"\").trim().toLowerCase();\n\n // 统一规整为 MailboxItem 标准模型\n const items: MailboxItem[] = availableMailboxes.map((m) => {\n if (typeof m === \"string\") {\n return { path: m, name: m };\n }\n return {\n path: m.path || \"\",\n name: m.name,\n specialUse: m.specialUse,\n };\n });\n\n // 1. 收件箱 (INBOX) 别名映射\n if (normalized === \"inbox\" || normalized === \"收件箱\") {\n const found = items.find(\n (m) =>\n m.specialUse?.toLowerCase() === \"\\\\inbox\" ||\n m.path?.toUpperCase() === \"INBOX\" ||\n m.name?.toUpperCase() === \"INBOX\"\n );\n return found ? found.path : \"INBOX\";\n }\n\n // 2. 草稿箱 (Drafts) 别名映射\n if (\n normalized === \"drafts\" ||\n normalized === \"draft\" ||\n normalized === \"草稿箱\" ||\n normalized === \"草稿\"\n ) {\n const bySpecialUse = items.find(\n (m) => m.specialUse?.toLowerCase() === \"\\\\drafts\"\n );\n if (bySpecialUse) {\n return bySpecialUse.path;\n }\n\n const byName = items.find((m) => {\n const p = m.path.toLowerCase();\n const n = (m.name || \"\").toLowerCase();\n return (\n p === \"drafts\" ||\n p === \"草稿箱\" ||\n p.endsWith(\"/drafts\") ||\n n === \"drafts\" ||\n n === \"草稿箱\"\n );\n });\n if (byName) {\n return byName.path;\n }\n\n return \"Drafts\";\n }\n\n // 3. 回收站 (Trash) 别名映射\n if (\n normalized === \"trash\" ||\n normalized === \"bin\" ||\n normalized === \"deleted\" ||\n normalized === \"已删除\" ||\n normalized === \"回收站\" ||\n normalized === \"废件箱\"\n ) {\n const bySpecialUse = items.find(\n (m) => m.specialUse?.toLowerCase() === \"\\\\trash\"\n );\n if (bySpecialUse) {\n return bySpecialUse.path;\n }\n\n const byName = items.find((m) => {\n const p = m.path.toLowerCase();\n const n = (m.name || \"\").toLowerCase();\n return (\n p === \"trash\" ||\n p === \"deleted messages\" ||\n p === \"已删除\" ||\n p === \"回收站\" ||\n p.endsWith(\"/trash\") ||\n n === \"trash\" ||\n n === \"已删除\" ||\n n === \"回收站\"\n );\n });\n if (byName) {\n return byName.path;\n }\n\n return \"Trash\";\n }\n\n // 4. 已发送 (Sent) 别名映射\n if (\n normalized === \"sent\" ||\n normalized === \"已发送\" ||\n normalized === \"sent messages\"\n ) {\n const bySpecialUse = items.find(\n (m) => m.specialUse?.toLowerCase() === \"\\\\sent\"\n );\n if (bySpecialUse) {\n return bySpecialUse.path;\n }\n\n const byName = items.find((m) => {\n const p = m.path.toLowerCase();\n const n = (m.name || \"\").toLowerCase();\n return (\n p === \"sent\" ||\n p === \"sent messages\" ||\n p === \"已发送\" ||\n p.endsWith(\"/sent mail\") ||\n p.endsWith(\"/sent\") ||\n n === \"sent\" ||\n n === \"已发送\"\n );\n });\n if (byName) {\n return byName.path;\n }\n\n return \"Sent\";\n }\n\n // 5. 尝试精确与不区分大小写匹配物理路径\n const exactMatch = items.find(\n (m) =>\n m.path.toLowerCase() === normalized ||\n (m.name && m.name.toLowerCase() === normalized)\n );\n if (exactMatch) {\n return exactMatch.path;\n }\n\n return logicalAlias;\n}\n\n/**\n * 使用 Nodemailer 纯内存流式传输器构建标准 RFC 822 MIME 数据 Buffer\n *\n * @param options 发信选项载荷\n * @param from 发件人地址\n * @returns 编译后的二进制 Buffer\n */\nexport async function buildRawMimeMessage(\n options: SendEmailOptions,\n from: string\n): Promise<Buffer> {\n const transport = nodemailer.createTransport({\n streamTransport: true,\n buffer: true,\n });\n\n let safeAttachments = options.attachments;\n if (options.attachments && options.attachments.length > 0) {\n safeAttachments = options.attachments.map((att) => {\n if (att.path) {\n const validated = validateOutboundAttachmentPath(att.path);\n return { ...att, path: validated };\n }\n return att;\n });\n }\n\n const mailOptions = {\n from,\n to: Array.isArray(options.to) ? options.to.join(\", \") : options.to,\n cc: options.cc\n ? Array.isArray(options.cc)\n ? options.cc.join(\", \")\n : options.cc\n : undefined,\n bcc: options.bcc\n ? Array.isArray(options.bcc)\n ? options.bcc.join(\", \")\n : options.bcc\n : undefined,\n subject: options.subject,\n text: options.text,\n html: options.html,\n attachments: safeAttachments,\n inReplyTo: options.inReplyTo,\n references: options.references,\n };\n\n const info = await transport.sendMail(mailOptions);\n return info.message as Buffer;\n}\n\n/**\n * 净化邮件正文文本并提取 150 字符 Preview 预览摘要\n *\n * @param raw 原始正文文本或 HTML 字符串或 Buffer\n * @param maxLength 最大摘要字数(默认 150 字符)\n * @returns 净化后的纯文本预览摘要\n */\nexport function extractPreviewSnippet(\n raw: string | Buffer | undefined,\n maxLength = 150\n): string {\n if (!raw) return \"\";\n let text = typeof raw === \"string\" ? raw : raw.toString(\"utf-8\");\n\n // 1. 去除 style 与 script 标签及其内部脚本/样式内容\n text = text.replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, \"\");\n text = text.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, \"\");\n\n // 2. 去除所有 HTML 结构标签\n text = text.replace(/<[^>]+>/g, \" \");\n\n // 3. 常见 HTML 实体字符还原解码\n text = text\n .replace(/&nbsp;/gi, \" \")\n .replace(/&amp;/gi, \"&\")\n .replace(/&lt;/gi, \"<\")\n .replace(/&gt;/gi, \">\")\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\");\n\n // 4. 压缩换行与多余空白符,保证 Preview 纯净单行紧凑\n const cleaned = text.replace(/\\s+/g, \" \").trim();\n if (cleaned.length <= maxLength) {\n return cleaned;\n }\n return cleaned.slice(0, maxLength) + \"...\";\n}\n\n/**\n * 从 IMAP fetch 的 bodyParts 集合或 raw source 提取正文文本内容\n *\n * @param bodyParts 可选的 Map 形式的 bodyParts\n * @param source 可选的 raw source Buffer\n * @returns 提取的文本字符串\n */\nexport function parseBodyFromRawOrParts(\n bodyParts?: Map<string, Buffer>,\n source?: Buffer\n): string {\n // 1. 优先尝试从 bodyParts 获取 TEXT 或第一正文分块\n if (bodyParts) {\n const textPart = bodyParts.get(\"TEXT\") || bodyParts.get(\"1\");\n if (textPart) {\n return textPart.toString(\"utf-8\");\n }\n }\n\n // 2. 回退从 source 剥离邮件头提取正文前缀\n if (source) {\n const raw = source.toString(\"utf-8\");\n const headerSplit = raw.indexOf(\"\\r\\n\\r\\n\");\n if (headerSplit !== -1) {\n return raw.slice(headerSplit + 4);\n }\n const lfSplit = raw.indexOf(\"\\n\\n\");\n if (lfSplit !== -1) {\n return raw.slice(lfSplit + 2);\n }\n }\n\n return \"\";\n}\n\n","/**\n * 附件受管沙箱存储服务,提供目录隔离、文件名净化与防路径穿越校验\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * 获取当前受管附件沙箱的物理根目录\n *\n * 优先使用环境变量 MCP_ATTACHMENT_DIR,未配置时回退至系统临时目录下的独立隔离沙箱。\n *\n * @returns 沙箱根目录物理绝对路径\n */\nexport function getAttachmentSandboxDir(): string {\n const customDir = process.env.MCP_ATTACHMENT_DIR;\n if (customDir && customDir.trim().length > 0) {\n return path.resolve(customDir.trim());\n }\n return path.resolve(os.tmpdir(), \"mcp-email-attachments\");\n}\n\n/**\n * 严格净化原始附件文件名,剔除路径分隔符与危险字符\n *\n * @param rawName 原始附件文件名\n * @returns 净化后的安全纯文件名\n * @throws Error 当文件名包含恶意路径逃逸特征时\n */\nexport function sanitizeFileName(rawName: string): string {\n if (!rawName || typeof rawName !== \"string\") {\n return `attachment-${Date.now()}`;\n }\n\n // 1. 深度检测显式路径穿越标记与空字节逃逸\n if (rawName.includes(\"..\") || rawName.includes(\"\\0\")) {\n throw new Error(`拒绝处理:检测到非法路径穿越文件名 \"${rawName}\"`);\n }\n\n // 2. 剥离可能存在的路径前缀,仅保留基名(兼容正反斜杠)\n const normalized = rawName.replace(/\\\\/g, \"/\");\n let cleanName = path.posix.basename(normalized);\n\n // 3. 过滤系统保留控制字符与危险字符\n cleanName = cleanName.replace(/[\\x00-\\x1f\\x7f<>:\"/\\\\|?*]/g, \"_\").trim();\n\n // 4. 若过滤后文件名为空或仅有点号,回退安全默认名称\n if (!cleanName || cleanName === \".\" || cleanName === \"..\") {\n cleanName = `attachment-${Date.now()}`;\n }\n\n return cleanName;\n}\n\n/**\n * 将附件二进制数据保存至受管沙箱物理目录\n *\n * @param rawFileName 原始文件名\n * @param content 二进制内容 Buffer 或 Uint8Array\n * @param customSandboxDir 可选的自定义沙箱目录(供测试与特定场景注入)\n * @param uid 可选的邮件 UID 标识,用于按邮件分层子目录隔离防同名覆盖\n * @returns 落盘结果信息,包含物理绝对路径与 file:/// 直达 URI\n * @throws Error 当目标路径试图越界逃逸沙箱根目录时\n */\nexport async function saveAttachmentToSandbox(\n rawFileName: string,\n content: Buffer | Uint8Array,\n customSandboxDir?: string,\n uid?: number | string\n): Promise<{ filePath: string; fileUrl: string; filename: string; size: number }> {\n // 1. 解析沙箱绝对根路径并确保目录存在\n const sandboxDir = path.resolve(customSandboxDir || getAttachmentSandboxDir());\n const targetDir = uid !== undefined ? path.join(sandboxDir, String(uid)) : sandboxDir;\n await fs.mkdir(targetDir, { recursive: true });\n\n // 2. 净化文件名\n const safeFileName = sanitizeFileName(rawFileName);\n\n // 3. 构建物理目标路径并进行沙箱边界双重校验\n const targetPath = path.resolve(targetDir, safeFileName);\n const relative = path.relative(sandboxDir, targetPath);\n\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`安全防御触发:目标路径 \"${targetPath}\" 越界逃逸沙箱根目录 \"${sandboxDir}\"`);\n }\n\n // 4. 二进制写入落盘\n await fs.writeFile(targetPath, content);\n\n // 5. 生成标准 file:/// 协议直达链接\n const fileUrl = pathToFileURL(targetPath).toString();\n\n return {\n filePath: targetPath,\n fileUrl,\n filename: safeFileName,\n size: content.byteLength,\n };\n}\n\n/**\n * 校验待外发本地附件路径的安全性,防止敏感文件外发泄露\n *\n * 严格限制仅允许读取受管沙箱目录 (MCP_ATTACHMENT_DIR) 或当前工作区目录下的文件,\n * 严禁越界读取操作系统敏感文件(如 /etc/passwd、id_rsa)及环境变量配置文件 (.env*)。\n *\n * @param candidatePath 候选本地文件路径\n * @returns 规整后的绝对物理路径\n * @throws Error 当路径非法、不存在或超出安全白名单范围时\n */\nexport function validateOutboundAttachmentPath(candidatePath: string): string {\n if (!candidatePath || typeof candidatePath !== \"string\") {\n throw new Error(\"附件路径必须为有效的非空字符串\");\n }\n\n // 1. 拦截空字节注入\n if (candidatePath.includes(\"\\0\")) {\n throw new Error(\"非法附件路径:检测到空字节注入\");\n }\n\n const resolvedPath = path.resolve(candidatePath);\n const baseName = path.basename(resolvedPath).toLowerCase();\n\n // 2. 严格拦截关键敏感凭据与配置文件\n if (\n baseName.startsWith(\".env\") ||\n baseName === \"id_rsa\" ||\n baseName === \"id_ed25519\" ||\n baseName.endsWith(\".pem\") ||\n baseName.endsWith(\".key\") ||\n baseName === \"shadow\" ||\n baseName === \"passwd\" ||\n baseName === \"sam\" ||\n baseName === \"system\"\n ) {\n throw new Error(`安全拦截:严禁外发系统关键敏感凭据文件 \"${baseName}\"`);\n }\n\n // 3. 白名单根目录校验:受管沙箱目录或当前运行工作区目录\n const sandboxDir = getAttachmentSandboxDir();\n const cwdDir = process.cwd();\n\n const relSandbox = path.relative(sandboxDir, resolvedPath);\n const inSandbox = !relSandbox.startsWith(\"..\") && !path.isAbsolute(relSandbox);\n\n const relCwd = path.relative(cwdDir, resolvedPath);\n const inCwd = !relCwd.startsWith(\"..\") && !path.isAbsolute(relCwd);\n\n if (!inSandbox && !inCwd) {\n throw new Error(\n `安全拦截:待外发附件路径 \"${candidatePath}\" 超出允许的安全目录边界(仅允许当前工作区或沙箱附件目录)`\n );\n }\n\n return resolvedPath;\n}\n","/**\n * 邮件正文提纯清洗、轻量 Markdown 转换与 30KB 安全截断\n *\n * @author Ateng\n * @since 2026-10-08\n */\n\n/** 邮件正文最大允许字节数 (30KB) */\nexport const MAX_EMAIL_BODY_BYTES = 30 * 1024;\n\n/** 超长正文安全截断提示声明 */\nexport const TRUNCATION_NOTICE = \"\\n\\n[提示: 邮件正文已超过 30KB 安全阈值,已执行截断保护]\";\n\n/**\n * 将 HTML 富文本清洗转换为结构清晰的轻量 Markdown 或纯文本\n *\n * @param html 原始 HTML 字符串\n * @returns 转换后的 Markdown/纯文本\n */\nexport function htmlToMarkdown(html: string): string {\n if (!html) return \"\";\n\n let text = html;\n\n // 1. 去除头部结构与无意义样式、脚本\n text = text.replace(/<head[^>]*>[\\s\\S]*?<\\/head>/gi, \"\");\n text = text.replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, \"\");\n text = text.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, \"\");\n\n // 2. 转换常见排版与语义标签为 Markdown 格式\n text = text.replace(/<h1\\b[^>]*>([\\s\\S]*?)<\\/h1>/gi, \"\\n# $1\\n\");\n text = text.replace(/<h2\\b[^>]*>([\\s\\S]*?)<\\/h2>/gi, \"\\n## $1\\n\");\n text = text.replace(/<h3\\b[^>]*>([\\s\\S]*?)<\\/h3>/gi, \"\\n### $1\\n\");\n text = text.replace(/<h4\\b[^>]*>([\\s\\S]*?)<\\/h4>/gi, \"\\n#### $1\\n\");\n text = text.replace(/<h5\\b[^>]*>([\\s\\S]*?)<\\/h5>/gi, \"\\n##### $1\\n\");\n text = text.replace(/<h6\\b[^>]*>([\\s\\S]*?)<\\/h6>/gi, \"\\n###### $1\\n\");\n\n text = text.replace(/<(b|strong)\\b[^>]*>([\\s\\S]*?)<\\/\\1>/gi, \"**$2**\");\n text = text.replace(/<(i|em)\\b[^>]*>([\\s\\S]*?)<\\/\\1>/gi, \"*$2*\");\n text = text.replace(/<a\\b[^>]*href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi, \"[$2]($1)\");\n\n text = text.replace(/<li\\b[^>]*>([\\s\\S]*?)<\\/li>/gi, \"\\n- $1\");\n text = text.replace(/<hr\\b[^>]*\\/?>/gi, \"\\n---\\n\");\n text = text.replace(/<br\\b[^>]*\\/?>/gi, \"\\n\");\n text = text.replace(/<\\/(p|div|tr)>/gi, \"\\n\");\n\n\n // 3. 剥离剩余所有 HTML 标签\n text = text.replace(/<[^>]+>/g, \"\");\n\n // 4. 常见 HTML 实体还原\n text = text\n .replace(/&nbsp;/gi, \" \")\n .replace(/&amp;/gi, \"&\")\n .replace(/&lt;/gi, \"<\")\n .replace(/&gt;/gi, \">\")\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\");\n\n // 5. 规整空行与行首尾空白\n const lines = text.split(\"\\n\").map((line) => line.trim());\n const cleanLines: string[] = [];\n let prevEmpty = false;\n\n for (const line of lines) {\n if (line.length === 0) {\n if (!prevEmpty) {\n cleanLines.push(\"\");\n prevEmpty = true;\n }\n } else {\n cleanLines.push(line);\n prevEmpty = false;\n }\n }\n\n return cleanLines.join(\"\\n\").trim();\n}\n\n/**\n * 提纯清洗邮件正文并执行 30KB 安全截断\n *\n * @param text 邮件纯文本内容(如有)\n * @param html 邮件 HTML 内容(如有)\n * @returns 提纯后的正文与是否发生截断标识\n */\nexport function purifyEmailBody(\n text?: string,\n html?: string\n): { content: string; truncated: boolean } {\n // 1. 优先使用已转换的 Markdown 或提取的纯文本\n let rawContent = \"\";\n if (html && html.trim().length > 0) {\n rawContent = htmlToMarkdown(html);\n } else if (text && text.trim().length > 0) {\n rawContent = text.trim();\n }\n\n // 2. 检验 UTF-8 字节大小并执行截断\n const byteLength = Buffer.byteLength(rawContent, \"utf-8\");\n\n if (byteLength > MAX_EMAIL_BODY_BYTES) {\n const buffer = Buffer.from(rawContent, \"utf-8\");\n // 安全截取前 MAX_EMAIL_BODY_BYTES 字节,并过滤不完整字符\n const sliced = buffer.subarray(0, MAX_EMAIL_BODY_BYTES);\n const truncatedText = sliced.toString(\"utf-8\");\n\n return {\n content: truncatedText + TRUNCATION_NOTICE,\n truncated: true,\n };\n }\n\n return {\n content: rawContent,\n truncated: false,\n };\n}\n","/**\n * SMTP 邮件外发核心业务服务\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport nodemailer, { type Transporter } from \"nodemailer\";\nimport { config } from \"../config/index.js\";\nimport type { SendEmailOptions, SmtpConfig } from \"../types/index.js\";\nimport { validateOutboundAttachmentPath } from \"./attachment-sandbox.js\";\n\n/**\n * SMTP 传输管理服务\n */\nexport class SmtpService {\n private transporter: Transporter | null = null;\n\n constructor(private readonly smtpConfig?: SmtpConfig) {}\n\n /**\n * 初始化并获取 Nodemailer 传输器单例\n *\n * @returns 初始化的 Transporter 实例\n * @throws Error 当未配置 SMTP 主机或账号时\n */\n private getTransporter(): Transporter {\n if (this.transporter) {\n return this.transporter;\n }\n\n const host = this.smtpConfig?.host || config.MCP_SMTP_HOST;\n const port = this.smtpConfig?.port ?? config.MCP_SMTP_PORT;\n const secure = this.smtpConfig?.secure ?? config.MCP_SMTP_SECURE;\n const user = this.smtpConfig?.user || config.MCP_SMTP_USER;\n const pass = this.smtpConfig?.pass || config.MCP_SMTP_PASS;\n\n if (!host || !user || !pass) {\n throw new Error(\n \"SMTP 配置不完整:请确保已配置 MCP_SMTP_HOST、MCP_SMTP_USER 和 MCP_SMTP_PASS 环境变量\"\n );\n }\n\n this.transporter = nodemailer.createTransport({\n host,\n port,\n secure,\n auth: {\n user,\n pass,\n },\n });\n\n return this.transporter;\n }\n\n /**\n * 发送电子邮件\n *\n * @param options 发送邮件配置与内容选项\n * @returns 发送结果明细,包含 messageId\n * @throws Error 当发送失败时\n */\n async sendEmail(options: SendEmailOptions): Promise<{ messageId: string; accepted: string[] }> {\n // 1. 获取并校验 SMTP 传输客户端\n const client = this.getTransporter();\n\n // 2. 校验外发附件路径安全性(防敏感数据泄露看门狗)\n let safeAttachments = options.attachments;\n if (options.attachments && options.attachments.length > 0) {\n safeAttachments = options.attachments.map((att) => {\n if (att.path) {\n const validated = validateOutboundAttachmentPath(att.path);\n return { ...att, path: validated };\n }\n return att;\n });\n }\n\n // 3. 组装发件人与信件载荷\n const from =\n options.from ||\n this.smtpConfig?.from ||\n this.smtpConfig?.user ||\n config.MCP_SMTP_FROM ||\n config.MCP_SMTP_USER;\n const mailOptions = {\n from,\n to: Array.isArray(options.to) ? options.to.join(\", \") : options.to,\n cc: options.cc ? (Array.isArray(options.cc) ? options.cc.join(\", \") : options.cc) : undefined,\n bcc: options.bcc ? (Array.isArray(options.bcc) ? options.bcc.join(\", \") : options.bcc) : undefined,\n subject: options.subject,\n text: options.text,\n html: options.html,\n attachments: safeAttachments,\n inReplyTo: options.inReplyTo,\n references: options.references,\n };\n\n // 3. 执行外发传输并返回结果\n const info = await client.sendMail(mailOptions);\n return {\n messageId: info.messageId,\n accepted: Array.isArray(info.accepted) ? (info.accepted as string[]) : [],\n };\n }\n\n /**\n * 验证 SMTP 服务的网络与认证联通性\n *\n * @returns 是否连接成功\n */\n async verifyConnection(): Promise<boolean> {\n const client = this.getTransporter();\n await client.verify();\n return true;\n }\n}\n\nexport const smtpService = new SmtpService();\n","/**\n * 多账户连接池与动态路由调度管理器\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport { config } from \"../config/index.js\";\nimport type {\n AccountProfile,\n ConnectionVerifyReport,\n SanitizedAccountProfile,\n} from \"../types/index.js\";\nimport { ImapService } from \"./imap.service.js\";\nimport { SmtpService } from \"./smtp.service.js\";\n\n/**\n * 账户管理与路由调度核心服务\n */\nexport class AccountManager {\n private readonly accounts = new Map<string, AccountProfile>();\n private readonly defaultAccountId: string;\n private readonly smtpPool = new Map<string, SmtpService>();\n private readonly imapPool = new Map<string, ImapService>();\n\n /**\n * 构造账户管理器实例\n *\n * @param accountList 预加载的账户画像列表,缺省为 config.accounts\n * @param defaultId 默认账户标识,缺省为 config.defaultAccountId\n */\n constructor(\n accountList: AccountProfile[] = config.accounts,\n defaultId: string = config.defaultAccountId\n ) {\n accountList.forEach((acc) => {\n this.accounts.set(acc.id, acc);\n });\n this.defaultAccountId = defaultId;\n }\n\n /**\n * 列出所有已配置的账户脱敏元数据(隐藏密码与授权码)\n *\n * @returns 脱敏账户画像列表\n */\n listAccounts(): SanitizedAccountProfile[] {\n const result: SanitizedAccountProfile[] = [];\n\n for (const [id, acc] of this.accounts.entries()) {\n const canSend = Boolean(acc.smtp);\n const canReceive = Boolean(acc.imap);\n const mode = canSend && canReceive ? \"full\" : canSend ? \"send_only\" : \"receive_only\";\n\n result.push({\n id,\n name: acc.name,\n email: acc.email || acc.smtp?.user || acc.imap?.user,\n isDefault: id === this.defaultAccountId,\n mode,\n capabilities: {\n canSend,\n canReceive,\n },\n smtp: acc.smtp\n ? {\n host: acc.smtp.host,\n port: acc.smtp.port,\n secure: acc.smtp.secure,\n user: acc.smtp.user,\n from: acc.smtp.from,\n }\n : undefined,\n imap: acc.imap\n ? {\n host: acc.imap.host,\n port: acc.imap.port,\n secure: acc.imap.secure,\n user: acc.imap.user,\n }\n : undefined,\n });\n }\n\n return result;\n }\n\n /**\n * 获取指定的账户画像,缺省时自动回退至默认账户\n *\n * @param accountId 可选的账户标识\n * @returns 目标账户完整画像\n * @throws Error 当未找到指定或默认账户配置时\n */\n getAccount(accountId?: string): AccountProfile {\n const targetId = accountId || this.defaultAccountId;\n const account = this.accounts.get(targetId);\n\n if (!account) {\n if (accountId) {\n throw new Error(\n `未找到指定标识为 \"${accountId}\" 的邮箱账户配置,请通过 list_accounts 查看可用画像`\n );\n }\n throw new Error(\n `未找到默认邮箱账户配置 (defaultId: \"${this.defaultAccountId}\"),请检查配置`\n );\n }\n\n return account;\n }\n\n /**\n * 根据账户标识路由并获取缓存的 SMTP 服务实例\n *\n * @param accountId 可选账户标识\n * @returns SMTP 服务实例\n */\n getSmtpService(accountId?: string): SmtpService {\n const account = this.getAccount(accountId);\n if (!account.smtp) {\n throw new Error(\n `账户 \"${account.id}\" 未配置 SMTP 外发服务(当前处于纯收信模式)。如需查阅邮件请调用 search_emails 工具;如需外发邮件,请在配置中补充 MCP_SMTP_* 环境变量。`\n );\n }\n\n let service = this.smtpPool.get(account.id);\n if (!service) {\n service = new SmtpService(account.smtp);\n this.smtpPool.set(account.id, service);\n }\n\n return service;\n }\n\n /**\n * 根据账户标识路由并获取缓存的 IMAP 服务实例\n *\n * @param accountId 可选账户标识\n * @returns IMAP 服务实例\n */\n getImapService(accountId?: string): ImapService {\n const account = this.getAccount(accountId);\n if (!account.imap) {\n throw new Error(\n `账户 \"${account.id}\" 未配置 IMAP 查收服务(当前处于纯发信模式)。如需外发邮件请调用 send_email 工具;如需查阅或检索邮件,请在配置中补充 MCP_IMAP_* 环境变量。`\n );\n }\n\n let service = this.imapPool.get(account.id);\n if (!service) {\n service = new ImapService(account.imap);\n this.imapPool.set(account.id, service);\n }\n\n return service;\n }\n\n /**\n * 对指定或默认账户执行网络连通性与认证体检\n *\n * @param accountId 可选账户标识\n * @returns 综合体检诊断报告\n */\n async verifyConnection(accountId?: string): Promise<ConnectionVerifyReport> {\n const account = this.getAccount(accountId);\n\n // 1. SMTP 协议握手与认证体检\n const smtpResult: ConnectionVerifyReport[\"smtp\"] = {\n configured: Boolean(account.smtp),\n success: false,\n host: account.smtp?.host,\n port: account.smtp?.port,\n };\n\n if (account.smtp) {\n try {\n const smtpClient = this.getSmtpService(account.id);\n await smtpClient.verifyConnection();\n smtpResult.success = true;\n } catch (err: unknown) {\n smtpResult.error = err instanceof Error ? err.message : String(err);\n }\n }\n\n // 2. IMAP 协议握手与认证体检\n const imapResult: ConnectionVerifyReport[\"imap\"] = {\n configured: Boolean(account.imap),\n success: false,\n host: account.imap?.host,\n port: account.imap?.port,\n };\n\n if (account.imap) {\n try {\n const imapClient = this.getImapService(account.id);\n await imapClient.verifyConnection();\n imapResult.success = true;\n } catch (err: unknown) {\n imapResult.error = err instanceof Error ? err.message : String(err);\n }\n }\n\n // 3. 综合判断体检结果\n const overallSuccess =\n (!smtpResult.configured || smtpResult.success) &&\n (!imapResult.configured || imapResult.success) &&\n (smtpResult.configured || imapResult.configured);\n\n // 4. 生成人性化综合诊断说明\n let message: string | undefined;\n if (overallSuccess) {\n if (smtpResult.configured && imapResult.configured) {\n message = \"SMTP 与 IMAP 双通道握手与认证体检均通过\";\n } else if (smtpResult.configured) {\n message = \"SMTP 外发通道连通性验证成功(当前账户处于纯发信模式,未配置 IMAP 查收通道)\";\n } else if (imapResult.configured) {\n message = \"IMAP 查收通道连通性验证成功(当前账户处于纯收信模式,未配置 SMTP 外发通道)\";\n }\n } else {\n const failures: string[] = [];\n if (smtpResult.configured && !smtpResult.success) {\n failures.push(`SMTP 验证失败: ${smtpResult.error || \"未知异常\"}`);\n }\n if (imapResult.configured && !imapResult.success) {\n failures.push(`IMAP 验证失败: ${imapResult.error || \"未知异常\"}`);\n }\n if (!smtpResult.configured && !imapResult.configured) {\n failures.push(\"未配置任何 SMTP 或 IMAP 服务参数\");\n }\n message = failures.join(\"; \");\n }\n\n return {\n account: account.id,\n smtp: smtpResult,\n imap: imapResult,\n overallSuccess,\n message,\n };\n }\n}\n\nexport const accountManager = new AccountManager();\n","/**\n * 邮件会话回复与线程关系维护服务\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport type { AccountProfile } from \"../types/index.js\";\nimport type { ImapService } from \"./imap.service.js\";\nimport type { SmtpService } from \"./smtp.service.js\";\n\n/**\n * 邮件回复入参选项\n */\nexport interface ReplyEmailOptions {\n /** 被回复原邮件的 UID */\n originalUid: number;\n /** 原邮件所在邮箱(默认 INBOX) */\n mailbox?: string;\n /** 纯文本正文内容 */\n text?: string;\n /** HTML 格式正文内容 */\n html?: string;\n /** 是否全员回复(包含原邮件抄送人) */\n replyAll?: boolean;\n /** 附件清单 */\n attachments?: Array<{\n filename: string;\n path?: string;\n content?: string;\n contentType?: string;\n }>;\n}\n\n/**\n * 邮件回复响应结果\n */\nexport interface ReplyEmailResult {\n /** 新发出的邮件 Message-ID */\n messageId: string;\n /** 投递成功的收件地址列表 */\n accepted: string[];\n /** 关联回复原邮件 Message-ID */\n inReplyTo?: string;\n /** 关联会话引用链 Message-ID 集合 */\n references?: string[];\n /** 主收件人地址 */\n to: string;\n /** 抄送地址列表 */\n cc?: string[];\n /** 最终回复邮件主题 */\n subject: string;\n}\n\n/**\n * 从可能包含显示名称的邮箱字符串中提取纯邮箱地址\n *\n * @param input 原始地址字符串,如 \"User <user@example.com>\" 或 \"user@example.com\"\n * @returns 规范化的纯邮箱地址\n */\nexport function extractEmailAddress(input: string): string {\n const match = input.match(/<([^>]+)>/);\n if (match && match[1]) {\n return match[1].trim().toLowerCase();\n }\n return input.trim().toLowerCase();\n}\n\n/**\n * 格式化回复邮件主题,自动规整 Re: 前缀且避免多重重复\n *\n * @param subject 原始邮件主题\n * @returns 规整后的回复邮件主题\n */\nexport function formatReplySubject(subject: string): string {\n const cleanSubject = (subject || \"\").trim();\n if (/^re:\\s*/i.test(cleanSubject)) {\n return cleanSubject;\n }\n return `Re: ${cleanSubject || \"(无主题)\"}`;\n}\n\n/**\n * 执行邮件会话回复逻辑,自动构建 RFC 线程关系与收件人拓扑\n *\n * @param options 回复选项\n * @param account 发送账户画像\n * @param imapService IMAP 查询服务实例\n * @param smtpService SMTP 发送服务实例\n * @returns 最终外发结果\n */\nexport async function replyEmail(\n options: ReplyEmailOptions,\n account: AccountProfile,\n imapService: ImapService,\n smtpService: SmtpService\n): Promise<ReplyEmailResult> {\n // 1. 获取原邮件详情与头信息\n const mailbox = options.mailbox || \"INBOX\";\n const original = await imapService.getEmailDetail(options.originalUid, mailbox);\n\n if (!original) {\n throw new Error(`未找到 UID 为 ${options.originalUid} 的原始邮件`);\n }\n\n // 2. 解析回复主收件人\n const to = original.fromAddress || extractEmailAddress(original.from);\n\n // 3. 构建全员回复 (replyAll) 抄送人列表,自动排除自身与原发件人\n let cc: string[] | undefined;\n if (options.replyAll) {\n const selfAddresses = new Set<string>();\n if (account.email) {\n selfAddresses.add(account.email.toLowerCase());\n }\n if (account.smtp?.user) {\n selfAddresses.add(account.smtp.user.toLowerCase());\n }\n if (account.imap?.user) {\n selfAddresses.add(account.imap.user.toLowerCase());\n }\n if (account.smtp?.from) {\n selfAddresses.add(extractEmailAddress(account.smtp.from));\n }\n\n const allOriginalRecipients = [...(original.to || []), ...(original.cc || [])];\n const ccSet = new Set<string>();\n\n for (const raw of allOriginalRecipients) {\n const email = extractEmailAddress(raw);\n if (email && email !== to && !selfAddresses.has(email)) {\n ccSet.add(email);\n }\n }\n\n if (ccSet.size > 0) {\n cc = Array.from(ccSet);\n }\n }\n\n // 4. 组装会话线程标识 (In-Reply-To & References) 与主题\n const inReplyTo = original.messageId;\n const references: string[] = original.references ? [...original.references] : [];\n if (original.messageId && !references.includes(original.messageId)) {\n references.push(original.messageId);\n }\n\n const subject = formatReplySubject(original.subject);\n\n // 5. 调用 SMTP 服务外发回复邮件\n const sendResult = await smtpService.sendEmail({\n to,\n cc,\n subject,\n text: options.text,\n html: options.html,\n attachments: options.attachments,\n inReplyTo,\n references: references.length > 0 ? references : undefined,\n });\n\n return {\n messageId: sendResult.messageId,\n accepted: sendResult.accepted,\n inReplyTo,\n references: references.length > 0 ? references : undefined,\n to,\n cc,\n subject,\n };\n}\n"],"mappings":"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","names":["z","fs","path","nodemailer","nodemailer","imapService","smtpService","z","smtpService","imapService"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config/index.ts","../src/tools/index.ts","../src/services/imap.service.ts","../src/services/mailbox-resolver.ts","../src/services/attachment-sandbox.ts","../src/services/content-purifier.ts","../src/services/smtp.service.ts","../src/services/account-manager.ts","../src/services/reply.service.ts"],"sourcesContent":["/**\n * MCP Server Email 服务主入口\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport http from \"node:http\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { config } from \"./config/index.js\";\nimport { registerEmailTools } from \"./tools/index.js\";\n\n/**\n * 启动 MCP 邮件服务端\n */\nasync function main(): Promise<void> {\n // 1. 初始化 MCP 服务端实例\n const server = new McpServer({\n name: \"mcp-server-email\",\n version: \"1.0.1\",\n });\n\n // 2. 注册邮件交互工具\n registerEmailTools(server);\n\n // 3. 命令行参数解析优先级高于环境变量\n const args = process.argv.slice(2);\n let transportMode = config.MCP_TRANSPORT;\n let port = config.MCP_PORT;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--transport\" && args[i + 1]) {\n transportMode = args[i + 1] === \"sse\" ? \"sse\" : \"stdio\";\n i++;\n } else if (args[i] === \"--port\" && args[i + 1]) {\n port = parseInt(args[i + 1], 10) || 3000;\n i++;\n }\n }\n\n // 4. 根据模式启动通信监听\n if (transportMode === \"sse\") {\n const sessions = new Map<string, SSEServerTransport>();\n\n const httpServer = http.createServer(async (req, res) => {\n const url = new URL(req.url || \"/\", `http://${req.headers.host || \"localhost\"}`);\n\n // 允许跨域调用 (CORS)\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204).end();\n return;\n }\n\n if (url.pathname === \"/sse\") {\n const transport = new SSEServerTransport(\"/messages\", res);\n sessions.set(transport.sessionId, transport);\n\n res.on(\"close\", () => {\n sessions.delete(transport.sessionId);\n console.error(`[MCP Email Server] SSE 会话已断开: ${transport.sessionId}`);\n });\n\n await server.connect(transport);\n console.error(`[MCP Email Server] SSE 传输连接已建立: ${transport.sessionId}`);\n } else if (url.pathname === \"/messages\" && req.method === \"POST\") {\n const sessionId = url.searchParams.get(\"sessionId\");\n const transport = sessionId\n ? sessions.get(sessionId)\n : sessions.values().next().value || null;\n\n if (transport) {\n await transport.handlePostMessage(req, res);\n } else {\n res\n .writeHead(400, { \"Content-Type\": \"text/plain; charset=utf-8\" })\n .end(\"无效或未找到对应的 SSE 传输会话\");\n }\n } else if (url.pathname === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n status: \"ok\",\n activeSessions: sessions.size,\n timestamp: new Date().toISOString(),\n })\n );\n } else {\n res.writeHead(404).end(\"Not Found\");\n }\n });\n\n httpServer.listen(port, () => {\n console.error(`[MCP Email Server] SSE 模式正在监听端口: ${port}`);\n });\n } else {\n // 默认 Stdio 模式 (标准输入输出,供本地 Claude Desktop / Cursor 进程拉起)\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[MCP Email Server] Stdio 传输已就绪,正在监听标准输入输出\");\n }\n}\n\nmain().catch((err: unknown) => {\n console.error(\"[MCP Email Server 崩溃]\", err);\n process.exit(1);\n});\n","/**\n * 服务端环境变量与多账户画像配置解析\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport { z } from \"zod\";\nimport type { AccountProfile } from \"../types/index.js\";\n\n// 加载本地环境变量\ndotenv.config();\n\n/**\n * SMTP 单配置 Schema\n */\nconst smtpProfileSchema = z.object({\n host: z.string(),\n port: z\n .union([z.number(), z.string().transform((val) => parseInt(val, 10))])\n .default(465),\n secure: z\n .union([z.boolean(), z.string().transform((val) => val === \"true\" || val === \"1\")])\n .default(true),\n user: z.string(),\n pass: z.string(),\n from: z.string().optional(),\n});\n\n/**\n * IMAP 单配置 Schema\n */\nconst imapProfileSchema = z.object({\n host: z.string(),\n port: z\n .union([z.number(), z.string().transform((val) => parseInt(val, 10))])\n .default(993),\n secure: z\n .union([z.boolean(), z.string().transform((val) => val === \"true\" || val === \"1\")])\n .default(true),\n user: z.string(),\n pass: z.string(),\n});\n\n/**\n * 完整账户画像 Schema\n */\nconst accountProfileSchema = z.object({\n id: z.string(),\n name: z.string().optional(),\n email: z.string().optional(),\n smtp: smtpProfileSchema.optional(),\n imap: imapProfileSchema.optional(),\n});\n\n/**\n * 环境变量顶层 Schema 定义\n */\nconst envSchema = z.object({\n // SMTP 配置 (向下兼容单账户)\n MCP_SMTP_HOST: z.string().optional(),\n MCP_SMTP_PORT: z\n .string()\n .optional()\n .transform((val) => (val ? parseInt(val, 10) : 465)),\n MCP_SMTP_SECURE: z\n .string()\n .optional()\n .transform((val) => val === undefined || val === \"true\" || val === \"1\"),\n MCP_SMTP_USER: z.string().optional(),\n MCP_SMTP_PASS: z.string().optional(),\n MCP_SMTP_FROM: z.string().optional(),\n\n // IMAP 配置 (向下兼容单账户)\n MCP_IMAP_HOST: z.string().optional(),\n MCP_IMAP_PORT: z\n .string()\n .optional()\n .transform((val) => (val ? parseInt(val, 10) : 993)),\n MCP_IMAP_SECURE: z\n .string()\n .optional()\n .transform((val) => val === undefined || val === \"true\" || val === \"1\"),\n MCP_IMAP_USER: z.string().optional(),\n MCP_IMAP_PASS: z.string().optional(),\n\n // 多账户配置\n MCP_ACCOUNTS: z.string().optional(),\n MCP_ACCOUNTS_FILE: z.string().optional(),\n MCP_DEFAULT_ACCOUNT: z.string().optional(),\n\n // MCP 传输与服务配置\n MCP_TRANSPORT: z.enum([\"stdio\", \"sse\"]).default(\"stdio\"),\n MCP_PORT: z\n .string()\n .optional()\n .transform((val) => (val ? parseInt(val, 10) : 3000)),\n MCP_LOG_LEVEL: z.string().default(\"info\"),\n});\n\nexport type AppConfig = z.infer<typeof envSchema> & {\n accounts: AccountProfile[];\n defaultAccountId: string;\n};\n\n/**\n * 将 JSON 数据解析为账户画像列表\n *\n * @param raw JSON 反序列化后的原始数据\n * @returns 规范化的账户画像列表\n */\nfunction parseAccountsFromJson(raw: unknown): AccountProfile[] {\n if (Array.isArray(raw)) {\n return z.array(accountProfileSchema).parse(raw);\n }\n if (typeof raw === \"object\" && raw !== null) {\n const record = z.record(accountProfileSchema.omit({ id: true })).parse(raw);\n return Object.entries(record).map(([id, profile]) => ({\n ...profile,\n id,\n }));\n }\n throw new Error(\"无效的账户配置格式,必须为 JSON 数组或键值对象\");\n}\n\n/**\n * 从环境变量与配置文件中解析多账户画像列表\n *\n * @param env 环境变量键值字典,缺省为 process.env\n * @returns 解析得到的账户列表与默认账户 ID\n */\nexport function parseAccountProfiles(\n env: Record<string, string | undefined> = process.env\n): { accounts: AccountProfile[]; defaultAccountId: string } {\n let accounts: AccountProfile[] = [];\n\n // 1. 优先尝试从 MCP_ACCOUNTS_FILE 配置文件加载\n const accountsFile = env.MCP_ACCOUNTS_FILE;\n if (accountsFile) {\n try {\n const resolvedPath = path.isAbsolute(accountsFile)\n ? accountsFile\n : path.resolve(process.cwd(), accountsFile);\n if (fs.existsSync(resolvedPath)) {\n const fileContent = fs.readFileSync(resolvedPath, \"utf-8\");\n accounts = parseAccountsFromJson(JSON.parse(fileContent));\n } else {\n console.error(`[配置警告] MCP_ACCOUNTS_FILE 指定的文件不存在: ${resolvedPath}`);\n }\n } catch (err: unknown) {\n console.error(\n \"[配置错误] 解析 MCP_ACCOUNTS_FILE 失败:\",\n err instanceof Error ? err.message : String(err)\n );\n }\n }\n\n // 2. 尝试从 MCP_ACCOUNTS 环境变量(JSON 字符串)解析\n const accountsJson = env.MCP_ACCOUNTS;\n if (accountsJson && accounts.length === 0) {\n try {\n accounts = parseAccountsFromJson(JSON.parse(accountsJson));\n } catch (err: unknown) {\n console.error(\n \"[配置错误] 解析 MCP_ACCOUNTS JSON 失败:\",\n err instanceof Error ? err.message : String(err)\n );\n }\n }\n\n // 3. 兼容单账户环境变量平滑回退 (MCP_SMTP_* / MCP_IMAP_*)\n if (accounts.length === 0) {\n const hasSmtp = Boolean(env.MCP_SMTP_HOST && env.MCP_SMTP_USER && env.MCP_SMTP_PASS);\n const hasImap = Boolean(env.MCP_IMAP_HOST && env.MCP_IMAP_USER && env.MCP_IMAP_PASS);\n\n if (hasSmtp || hasImap) {\n const defaultAccount: AccountProfile = {\n id: \"default\",\n name: \"默认邮箱账户\",\n email: env.MCP_SMTP_USER || env.MCP_IMAP_USER,\n };\n\n if (hasSmtp) {\n defaultAccount.smtp = {\n host: env.MCP_SMTP_HOST!,\n port: env.MCP_SMTP_PORT ? parseInt(env.MCP_SMTP_PORT, 10) : 465,\n secure:\n env.MCP_SMTP_SECURE === undefined ||\n env.MCP_SMTP_SECURE === \"true\" ||\n env.MCP_SMTP_SECURE === \"1\",\n user: env.MCP_SMTP_USER!,\n pass: env.MCP_SMTP_PASS!,\n from: env.MCP_SMTP_FROM,\n };\n }\n\n if (hasImap) {\n defaultAccount.imap = {\n host: env.MCP_IMAP_HOST!,\n port: env.MCP_IMAP_PORT ? parseInt(env.MCP_IMAP_PORT, 10) : 993,\n secure:\n env.MCP_IMAP_SECURE === undefined ||\n env.MCP_IMAP_SECURE === \"true\" ||\n env.MCP_IMAP_SECURE === \"1\",\n user: env.MCP_IMAP_USER!,\n pass: env.MCP_IMAP_PASS!,\n };\n }\n\n accounts.push(defaultAccount);\n }\n }\n\n // 4. 解析默认账户 ID\n let defaultAccountId = env.MCP_DEFAULT_ACCOUNT || \"\";\n if (!defaultAccountId || !accounts.some((a) => a.id === defaultAccountId)) {\n const defaultAcc = accounts.find((a) => a.id === \"default\");\n defaultAccountId = defaultAcc ? defaultAcc.id : accounts[0]?.id || \"default\";\n }\n\n return { accounts, defaultAccountId };\n}\n\n/**\n * 解析并获取已校验的环境变量与多账户配置\n *\n * @param env 环境变量键值字典,缺省为 process.env\n * @returns 结构化配置对象\n */\nexport function loadConfig(env: Record<string, string | undefined> = process.env): AppConfig {\n const result = envSchema.safeParse(env);\n if (!result.success) {\n console.error(\"[配置错误] 环境变量校验失败:\", result.error.format());\n throw new Error(\"环境变量格式无效,请检查 .env 配置\");\n }\n\n const { accounts, defaultAccountId } = parseAccountProfiles(env);\n\n return {\n ...result.data,\n accounts,\n defaultAccountId,\n };\n}\n\nexport const config = loadConfig();\n","/**\n * MCP 工具定义与请求分发注册\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { accountManager } from \"../services/account-manager.js\";\nimport { replyEmail } from \"../services/reply.service.js\";\n\n/**\n * 注册所有邮件相关的 MCP 工具到服务端实例\n *\n * @param server McpServer 实例\n */\nexport function registerEmailTools(server: McpServer): void {\n // 1. 列出可用邮箱账户画像(凭据脱敏)\n server.tool(\n \"list_accounts\",\n \"列出所有已配置的邮箱账户画像列表(凭据安全脱敏,隐藏密码),包含账户标识、邮箱地址、运行模式(full/send_only/receive_only)、收发能力特性与默认账户标记\",\n {},\n async () => {\n try {\n const accounts = accountManager.listAccounts();\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(accounts, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取账户列表失败: ${message}` }],\n };\n }\n }\n );\n\n // 2. 连通性自检与凭据体检工具\n server.tool(\n \"verify_connection\",\n \"验证指定或默认邮箱账户的网络连通性与认证凭据(支持全功能或纯发信模式,自动识别 SMTP 与 IMAP),返回网络握手与身份认证综合体检诊断报告\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时体检默认账户\"),\n },\n async (args) => {\n try {\n const report = await accountManager.verifyConnection(args.account);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(report, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `验证账户连接失败: ${message}` }],\n };\n }\n }\n );\n\n // 3. 发送邮件工具\n server.tool(\n \"send_email\",\n \"发送电子邮件,支持纯文本、HTML 正文以及文件附件\",\n {\n account: z.string().optional().describe(\"发信邮箱账户画像标识,缺省时使用默认账户\"),\n to: z.union([z.string(), z.array(z.string())]).describe(\"收件人邮箱地址,单个或数组\"),\n subject: z.string().describe(\"邮件主题\"),\n text: z.string().optional().describe(\"纯文本正文内容\"),\n html: z.string().optional().describe(\"HTML 格式正文内容\"),\n cc: z.union([z.string(), z.array(z.string())]).optional().describe(\"抄送邮箱地址\"),\n bcc: z.union([z.string(), z.array(z.string())]).optional().describe(\"密送邮箱地址\"),\n attachments: z\n .array(\n z.object({\n filename: z.string().describe(\"附件文件名\"),\n path: z.string().optional().describe(\"本地文件绝对路径\"),\n content: z.string().optional().describe(\"附件文本内容或 Base64 编码字符串\"),\n contentType: z.string().optional().describe(\"MIME 类型\"),\n })\n )\n .optional()\n .describe(\"附件列表\"),\n },\n async (args) => {\n try {\n const smtpService = accountManager.getSmtpService(args.account);\n const result = await smtpService.sendEmail({\n to: args.to,\n subject: args.subject,\n text: args.text,\n html: args.html,\n cc: args.cc,\n bcc: args.bcc,\n attachments: args.attachments,\n });\n\n return {\n content: [\n {\n type: \"text\",\n text: `邮件发送成功!MessageID: ${result.messageId},已投递至: ${result.accepted.join(\", \")}`,\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `发送邮件失败: ${message}` }],\n };\n }\n }\n );\n\n // 4. 会话回复工具\n server.tool(\n \"reply_email\",\n \"回复指定邮件,自动保持原生会话折叠树(自动注入 In-Reply-To、References 邮件头,添加 Re: 主题前缀,支持一键 replyAll 保留原抄送人)\",\n {\n account: z.string().optional().describe(\"发送回复的邮箱账户画像标识,缺省时使用默认账户\"),\n originalUid: z.number().describe(\"被回复原邮件的唯一 UID 标识符\"),\n mailbox: z.string().optional().default(\"INBOX\").describe(\"原邮件所在邮箱文件夹名称,默认为 INBOX\"),\n text: z.string().optional().describe(\"回复的纯文本正文内容\"),\n html: z.string().optional().describe(\"回复的 HTML 格式正文内容\"),\n replyAll: z.boolean().optional().default(false).describe(\"是否全员回复(抄送除自身外的原邮件收件人与抄送人)\"),\n attachments: z\n .array(\n z.object({\n filename: z.string().describe(\"附件文件名\"),\n path: z.string().optional().describe(\"本地文件绝对路径\"),\n content: z.string().optional().describe(\"附件文本内容或 Base64 编码字符串\"),\n contentType: z.string().optional().describe(\"MIME 类型\"),\n })\n )\n .optional()\n .describe(\"附件列表\"),\n },\n async (args) => {\n try {\n const account = accountManager.getAccount(args.account);\n const imapService = accountManager.getImapService(args.account);\n const smtpService = accountManager.getSmtpService(args.account);\n\n const result = await replyEmail(\n {\n originalUid: args.originalUid,\n mailbox: args.mailbox,\n text: args.text,\n html: args.html,\n replyAll: args.replyAll,\n attachments: args.attachments,\n },\n account,\n imapService,\n smtpService\n );\n\n return {\n content: [\n {\n type: \"text\",\n text: `邮件回复成功!MessageID: ${result.messageId},已回复至: ${result.to}${result.cc ? ` (抄送: ${result.cc.join(\", \")})` : \"\"},主题: ${result.subject}`,\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `回复邮件失败: ${message}` }],\n };\n }\n }\n );\n\n // 5. 保存至草稿箱工具\n server.tool(\n \"create_draft\",\n \"将拟定邮件存入邮箱草稿箱(Drafts),供人工在邮箱客户端中最终审阅确认后发出\",\n {\n account: z.string().optional().describe(\"草稿所属邮箱账户画像标识,缺省时使用默认账户\"),\n to: z.union([z.string(), z.array(z.string())]).optional().describe(\"收件人邮箱地址,单个或数组\"),\n subject: z.string().optional().default(\"(无主题)\").describe(\"邮件主题\"),\n text: z.string().optional().describe(\"纯文本正文内容\"),\n html: z.string().optional().describe(\"HTML 格式正文内容\"),\n cc: z.union([z.string(), z.array(z.string())]).optional().describe(\"抄送邮箱地址\"),\n bcc: z.union([z.string(), z.array(z.string())]).optional().describe(\"密送邮箱地址\"),\n attachments: z\n .array(\n z.object({\n filename: z.string().describe(\"附件文件名\"),\n path: z.string().optional().describe(\"本地文件绝对路径\"),\n content: z.string().optional().describe(\"附件文本内容或 Base64 编码字符串\"),\n contentType: z.string().optional().describe(\"MIME 类型\"),\n })\n )\n .optional()\n .describe(\"附件列表\"),\n },\n async (args) => {\n try {\n const account = accountManager.getAccount(args.account);\n const imapService = accountManager.getImapService(args.account);\n const from =\n account.smtp?.from ||\n account.smtp?.user ||\n account.email ||\n \"user@example.com\";\n\n const result = await imapService.createDraft(\n {\n to: args.to || \"\",\n subject: args.subject || \"(无主题)\",\n text: args.text,\n html: args.html,\n cc: args.cc,\n bcc: args.bcc,\n attachments: args.attachments,\n },\n from\n );\n\n return {\n content: [\n {\n type: \"text\",\n text: `草稿已成功保存至 [${result.mailbox}]!主题: ${args.subject || \"(无主题)\"}`,\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `保存草稿箱失败: ${message}` }],\n };\n }\n }\n );\n\n // 6. 极速状态看板工具\n server.tool(\n \"get_mailbox_status\",\n \"极速获取指定或全部邮箱文件夹的状态看板(包含总邮件数、未读邮件数与最近邮件数),毫秒级响应\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n mailbox: z\n .string()\n .optional()\n .describe(\n \"目标邮箱文件夹别名或物理路径(如 inbox, drafts, trash 或 INBOX),缺省时统计全部可用文件夹\"\n ),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const report = await imapService.getMailboxStatus(args.mailbox);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(report, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取邮箱状态失败: ${message}` }],\n };\n }\n }\n );\n\n // 7. 检索邮件列表工具 (多维复合检索与分页)\n server.tool(\n \"search_emails\",\n \"在邮箱中按多维条件检索邮件,返回包含 150 字符 Preview 纯文本摘要的分页列表\",\n {\n account: z.string().optional().describe(\"收信邮箱账户画像标识,缺省时使用默认账户\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"邮箱文件夹名称或别名(如 inbox, drafts, trash),默认为 INBOX\"),\n query: z.string().optional().describe(\"全文检索关键字(匹配发件人、主题或正文)\"),\n from: z.string().optional().describe(\"按发件人地址或关键字筛选\"),\n to: z.string().optional().describe(\"按收件人地址或关键字筛选\"),\n subject: z.string().optional().describe(\"按邮件主题关键字筛选\"),\n unseenOnly: z.boolean().optional().default(false).describe(\"是否仅查询未读邮件\"),\n flaggedOnly: z.boolean().optional().default(false).describe(\"是否仅查询星标/置顶邮件\"),\n hasAttachment: z.boolean().optional().describe(\"是否必须包含附件\"),\n since: z.string().optional().describe(\"起始日期筛选,格式如 YYYY-MM-DD\"),\n before: z.string().optional().describe(\"截止日期筛选,格式如 YYYY-MM-DD\"),\n page: z.number().optional().default(1).describe(\"当前页码,从 1 开始,默认 1\"),\n limit: z.number().optional().default(10).describe(\"每页拉取条数,默认 10\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.searchEmails({\n mailbox: args.mailbox,\n query: args.query,\n from: args.from,\n to: args.to,\n subject: args.subject,\n unseenOnly: args.unseenOnly,\n flaggedOnly: args.flaggedOnly,\n hasAttachment: args.hasAttachment,\n since: args.since,\n before: args.before,\n page: args.page,\n limit: args.limit,\n });\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `检索邮件列表失败: ${message}` }],\n };\n }\n }\n );\n\n\n // 7. 获取邮件正文及附件详情工具\n server.tool(\n \"get_email_detail\",\n \"根据邮件全局 UID 获取单封邮件的完整正文内容与附件清单\",\n {\n account: z.string().optional().describe(\"收信邮箱账户画像标识,缺省时使用默认账户\"),\n uid: z.number().describe(\"邮件的唯一 UID 标识符\"),\n mailbox: z.string().optional().default(\"INBOX\").describe(\"邮箱文件夹名称,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const detail = await imapService.getEmailDetail(args.uid, args.mailbox);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(detail, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取邮件详情失败: ${message}` }],\n };\n }\n }\n );\n\n // 8. 列出全部邮箱目录工具\n server.tool(\n \"list_mailboxes\",\n \"获取当前邮箱服务的所有可用文件夹/目录列表(如 INBOX, Sent, Trash 等)\",\n {\n account: z.string().optional().describe(\"收信邮箱账户画像标识,缺省时使用默认账户\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const mailboxes = await imapService.listMailboxes();\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(mailboxes, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `获取邮箱目录失败: ${message}` }],\n };\n }\n }\n );\n\n // 9. 下载附件至本地受管沙箱工具\n server.tool(\n \"download_attachment\",\n \"将指定邮件的附件按需提取并安全保存至本地受管沙箱目录,返回物理绝对路径与 file:/// 直达 URI\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uid: z.number().describe(\"邮件的唯一 UID 标识符\"),\n attachmentId: z\n .string()\n .describe(\"待下载附件的标识 ID(对应 get_email_detail 返回的附件 id,如 '0')或附件文件名\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"原邮件所在邮箱文件夹名称或别名,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.downloadAttachment(\n args.uid,\n args.attachmentId,\n args.mailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `下载附件失败: ${message}` }],\n };\n }\n }\n );\n\n // 10. 标记邮件已读/未读工具\n server.tool(\n \"mark_email_read\",\n \"对单封或批量邮件设置已读或未读标记(\\\\Seen),协助完成待办邮件分诊流转\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uids: z\n .union([z.number(), z.array(z.number())])\n .describe(\"单封邮件 UID(数字)或批量邮件 UID 数组(如 [101, 102])\"),\n read: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"是否标记为已读(true 为已读,false 为未读),默认为 true\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"目标邮箱文件夹别名或物理路径,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.markEmailRead(\n args.uids,\n args.read,\n args.mailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `标记已读状态失败: ${message}` }],\n };\n }\n }\n );\n\n // 11. 邮件星标/置顶标记工具\n server.tool(\n \"flag_email\",\n \"对单封或批量邮件设置或取消重要星标标记(\\\\Flagged),用于重点关注或待办标记\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uids: z\n .union([z.number(), z.array(z.number())])\n .describe(\"单封邮件 UID(数字)或批量邮件 UID 数组(如 [101, 102])\"),\n flagged: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"是否设置星标(true 为星标置顶,false 为取消星标),默认为 true\"),\n mailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"目标邮箱文件夹别名或物理路径,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.flagEmail(\n args.uids,\n args.flagged,\n args.mailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `设置星标状态失败: ${message}` }],\n };\n }\n }\n );\n\n // 12. 邮件跨文件夹移动与防灾软删除工具\n server.tool(\n \"move_email\",\n \"将单封或批量邮件移动至目标文件夹(如归档至 archive);彻底禁用物理硬删除,删除邮件请指定 targetMailbox 为 trash 进行安全软删除\",\n {\n account: z.string().optional().describe(\"邮箱账户画像标识,缺省时使用默认账户\"),\n uids: z\n .union([z.number(), z.array(z.number())])\n .describe(\"单封邮件 UID(数字)或批量邮件 UID 数组(如 [101, 102])\"),\n targetMailbox: z\n .string()\n .describe(\"目标邮箱文件夹别名或物理路径(如 trash 进行软删除,或 archive 归档)\"),\n sourceMailbox: z\n .string()\n .optional()\n .default(\"INBOX\")\n .describe(\"源邮箱文件夹别名或物理路径,默认为 INBOX\"),\n },\n async (args) => {\n try {\n const imapService = accountManager.getImapService(args.account);\n const result = await imapService.moveEmail(\n args.uids,\n args.targetMailbox,\n args.sourceMailbox\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n isError: true,\n content: [{ type: \"text\", text: `移动邮件失败: ${message}` }],\n };\n }\n }\n );\n}\n","/**\n * IMAP 邮件查收与检索服务\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport { ImapFlow } from \"imapflow\";\nimport { simpleParser } from \"mailparser\";\nimport { config } from \"../config/index.js\";\nimport type {\n DownloadAttachmentResult,\n EmailAttachmentMetadata,\n EmailDetail,\n EmailSummary,\n FlagEmailResult,\n ImapConfig,\n MailboxStatus,\n MailboxStatusReport,\n MarkEmailReadResult,\n MoveEmailResult,\n SearchEmailFilter,\n SearchEmailsResult,\n SendEmailOptions,\n} from \"../types/index.js\";\nimport {\n buildRawMimeMessage,\n extractPreviewSnippet,\n parseBodyFromRawOrParts,\n resolveSpecialMailbox,\n} from \"./mailbox-resolver.js\";\nimport { purifyEmailBody } from \"./content-purifier.js\";\nimport { saveAttachmentToSandbox } from \"./attachment-sandbox.js\";\n\n\n\n\n/**\n * IMAP 邮件存储交互服务\n */\nexport class ImapService {\n constructor(private readonly imapConfig?: ImapConfig) {}\n\n /**\n * 创建新的 IMAP 客户端连接\n *\n * @returns 初始化的 ImapFlow 客户端实例\n * @throws Error 当未配置 IMAP 主机或账号时\n */\n private createClient(): ImapFlow {\n const host = this.imapConfig?.host || config.MCP_IMAP_HOST;\n const port = this.imapConfig?.port ?? config.MCP_IMAP_PORT;\n const secure = this.imapConfig?.secure ?? config.MCP_IMAP_SECURE;\n const user = this.imapConfig?.user || config.MCP_IMAP_USER;\n const pass = this.imapConfig?.pass || config.MCP_IMAP_PASS;\n\n if (!host || !user || !pass) {\n throw new Error(\n \"IMAP 配置不完整:请确保已配置 MCP_IMAP_HOST、MCP_IMAP_USER 和 MCP_IMAP_PASS 环境变量\"\n );\n }\n\n return new ImapFlow({\n host,\n port,\n secure,\n auth: {\n user,\n pass,\n },\n logger: false, // 禁用内部控制台输出,保护 MCP Stdio 通信通道\n });\n }\n\n /**\n * 获取远程邮箱目录列表\n *\n * @returns 邮箱目录路径列表\n */\n async listMailboxes(): Promise<string[]> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n return mailboxes.map((item) => item.path);\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 检索符合条件的邮件摘要列表\n *\n * @param filter 检索与过滤条件\n * @returns 分页检索结果与条目摘要\n */\n async searchEmails(filter: SearchEmailFilter): Promise<SearchEmailsResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n // 1. 获取物理邮箱列表并解析逻辑别名\n const allMailboxes = await client.list();\n const targetMailbox = resolveSpecialMailbox(filter.mailbox || \"INBOX\", allMailboxes);\n\n const lock = await client.getMailboxLock(targetMailbox);\n try {\n // 2. 组装 IMAP 查询条件字典\n const query: Record<string, unknown> = {};\n\n if (filter.query) {\n query.body = filter.query;\n }\n if (filter.unseenOnly) {\n query.seen = false;\n }\n if (filter.flaggedOnly) {\n query.flagged = true;\n }\n if (filter.from) {\n query.from = filter.from;\n }\n if (filter.to) {\n query.to = filter.to;\n }\n if (filter.subject) {\n query.subject = filter.subject;\n }\n if (filter.since) {\n query.since = new Date(filter.since);\n }\n if (filter.before) {\n query.before = new Date(filter.before);\n }\n\n const searchCriteria = Object.keys(query).length > 0 ? query : { all: true };\n const searchResult = await client.search(searchCriteria, { uid: true });\n const uids: number[] = Array.isArray(searchResult) ? searchResult : [];\n\n const total = uids.length;\n const page = filter.page && filter.page > 0 ? filter.page : 1;\n const limit = filter.limit && filter.limit > 0 ? filter.limit : 10;\n\n if (total === 0) {\n return {\n items: [],\n total: 0,\n page,\n limit,\n hasMore: false,\n };\n }\n\n // 3. 计算分页切片与拉取条目\n const sortedUids = [...uids].reverse();\n let selectedUids: number[] = [];\n let effectiveTotal = total;\n let hasMore = false;\n\n if (filter.hasAttachment === undefined) {\n // 常规无附件过滤场景:直接高效分页切片\n const startIndex = (page - 1) * limit;\n selectedUids = sortedUids.slice(startIndex, startIndex + limit);\n hasMore = startIndex + limit < total;\n } else {\n // 带有附件过滤场景:窗口探测回填(最大探测深度 100 封,消除分页稀疏断层)\n const maxScanLimit = Math.min(sortedUids.length, 100);\n const scanUids = sortedUids.slice(0, maxScanLimit);\n const matchedUids: number[] = [];\n\n if (scanUids.length > 0) {\n for await (const message of client.fetch(\n scanUids,\n {\n uid: true,\n bodyStructure: true,\n },\n { uid: true }\n )) {\n const hasAttachments = Boolean(\n message.bodyStructure?.childNodes &&\n message.bodyStructure.childNodes.length > 1\n );\n if (hasAttachments === filter.hasAttachment) {\n matchedUids.push(message.uid);\n }\n }\n }\n\n // 保持逆序排布(最新邮件优先)\n matchedUids.sort((a, b) => b - a);\n effectiveTotal = matchedUids.length;\n const startIndex = (page - 1) * limit;\n selectedUids = matchedUids.slice(startIndex, startIndex + limit);\n hasMore = startIndex + limit < matchedUids.length;\n }\n\n const items: EmailSummary[] = [];\n\n if (selectedUids.length > 0) {\n for await (const message of client.fetch(\n selectedUids,\n {\n envelope: true,\n flags: true,\n internalDate: true,\n uid: true,\n bodyStructure: true,\n bodyParts: [\"TEXT\", \"1\"],\n source: { maxLength: 2048 },\n },\n { uid: true }\n )) {\n const hasAttachments = Boolean(\n message.bodyStructure?.childNodes &&\n message.bodyStructure.childNodes.length > 1\n );\n\n const fromAddr = message.envelope?.from?.[0]\n ? `${message.envelope.from[0].name || \"\"} <${message.envelope.from[0].address || \"\"}>`.trim()\n : \"未知发件人\";\n\n // 提取正文并清洗为 150 字符 Preview 摘要\n const rawBody = parseBodyFromRawOrParts(message.bodyParts, message.source);\n const preview = extractPreviewSnippet(rawBody, 150);\n\n items.push({\n uid: message.uid,\n seq: message.seq,\n from: fromAddr,\n subject: message.envelope?.subject || \"(无主题)\",\n date: message.envelope?.date?.toISOString() || new Date().toISOString(),\n unseen: !message.flags?.has(\"\\\\Seen\"),\n hasAttachments,\n preview,\n });\n }\n\n // 保证返回项顺序与 selectedUids 顺序一致\n items.sort((a, b) => b.uid - a.uid);\n }\n\n return {\n items,\n total: effectiveTotal,\n page,\n limit,\n hasMore,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n\n }\n\n /**\n * 根据 UID 获取邮件正文及附件明细(包含 Markdown 提纯与附件元数据清单)\n *\n * @param uid 邮件唯一标识符\n * @param mailbox 所处邮箱文件夹或别名,默认 INBOX\n * @returns 邮件详情数据\n */\n async getEmailDetail(uid: number, mailbox = \"INBOX\"): Promise<EmailDetail> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const targetMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(targetMailbox);\n try {\n const download = await client.download(String(uid), undefined, { uid: true });\n if (!download || !download.content) {\n throw new Error(`未找到 UID 为 ${uid} 的邮件内容`);\n }\n\n const parsed = await simpleParser(download.content);\n\n const toList: string[] = [];\n if (parsed.to) {\n if (Array.isArray(parsed.to)) {\n parsed.to.forEach((addr) => toList.push(addr.text));\n } else {\n toList.push(parsed.to.text);\n }\n }\n\n const ccList: string[] = [];\n if (parsed.cc) {\n if (Array.isArray(parsed.cc)) {\n parsed.cc.forEach((addr) => ccList.push(addr.text));\n } else {\n ccList.push(parsed.cc.text);\n }\n }\n\n // 仅提取轻量元数据清单,严禁嵌入大体积 Base64,保护 Token 经济性\n const attachments: EmailAttachmentMetadata[] = (parsed.attachments || []).map((att, idx) => ({\n id: String(idx),\n filename: att.filename || `attachment-${idx}`,\n contentType: att.contentType || \"application/octet-stream\",\n size: att.size || (att.content ? att.content.length : 0),\n }));\n\n const fromAddress = parsed.from?.value?.[0]?.address || undefined;\n let references: string[] | undefined;\n if (parsed.references) {\n references = Array.isArray(parsed.references)\n ? parsed.references\n : [parsed.references];\n }\n\n // 清洗提纯 HTML 为轻量 Markdown,执行 30KB 安全截断\n const purified = purifyEmailBody(\n parsed.text,\n typeof parsed.html === \"string\" ? parsed.html : undefined\n );\n\n return {\n uid,\n from: parsed.from?.text || \"未知发件人\",\n fromAddress,\n to: toList,\n cc: ccList.length > 0 ? ccList : undefined,\n subject: parsed.subject || \"(无主题)\",\n date: parsed.date ? parsed.date.toISOString() : new Date().toISOString(),\n text: parsed.text,\n html: typeof parsed.html === \"string\" ? parsed.html : undefined,\n bodyMarkdown: purified.content,\n truncated: purified.truncated,\n messageId: parsed.messageId,\n inReplyTo: parsed.inReplyTo,\n references,\n attachments,\n };\n\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 从指定邮件中提取附件并下载保存至受管本地沙箱\n *\n * @param uid 邮件唯一标识符\n * @param attachmentIdentifier 附件唯一标识(ID 序号或文件名)\n * @param mailbox 所在邮箱文件夹,默认 INBOX\n * @returns 下载落盘结果\n * @throws Error 当未找到邮件或目标附件时\n */\n async downloadAttachment(\n uid: number,\n attachmentIdentifier: string,\n mailbox = \"INBOX\"\n ): Promise<DownloadAttachmentResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const targetMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(targetMailbox);\n try {\n const download = await client.download(String(uid), undefined, { uid: true });\n if (!download || !download.content) {\n throw new Error(`未找到 UID 为 ${uid} 的邮件内容`);\n }\n\n const parsed = await simpleParser(download.content);\n const attachments = parsed.attachments || [];\n\n // 优先通过数字索引匹配,其次匹配文件名\n const targetIndex = attachments.findIndex(\n (att, idx) =>\n String(idx) === String(attachmentIdentifier) ||\n att.filename === attachmentIdentifier\n );\n\n if (targetIndex === -1) {\n throw new Error(\n `未在邮件 (UID: ${uid}) 中找到标识为 \"${attachmentIdentifier}\" 的附件`\n );\n }\n\n const targetAttachment = attachments[targetIndex];\n if (!targetAttachment.content) {\n throw new Error(\n `附件 \"${targetAttachment.filename || attachmentIdentifier}\" 内容为空或无法提取`\n );\n }\n\n const rawFileName = targetAttachment.filename || `attachment-${targetIndex}`;\n const saved = await saveAttachmentToSandbox(rawFileName, targetAttachment.content, undefined, uid);\n\n return {\n attachmentId: String(targetIndex),\n filename: saved.filename,\n contentType: targetAttachment.contentType || \"application/octet-stream\",\n size: saved.size,\n filePath: saved.filePath,\n fileUrl: saved.fileUrl,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 验证 IMAP 服务的网络握手与身份认证\n *\n * @returns 是否连接成功\n */\n async verifyConnection(): Promise<boolean> {\n const client = this.createClient();\n try {\n await client.connect();\n return true;\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 将邮件载荷组装为 RFC 822 MIME 数据并存入草稿箱\n *\n * @param options 邮件选项载荷\n * @param from 发件人地址\n * @returns 存储结果,包含物理草稿箱路径\n */\n async createDraft(\n options: SendEmailOptions,\n from: string\n ): Promise<{ success: boolean; mailbox: string }> {\n const client = this.createClient();\n await client.connect();\n\n try {\n // 1. 获取邮箱列表并解析物理草稿箱路径\n const mailboxes = await client.list();\n const draftsPath = resolveSpecialMailbox(\"drafts\", mailboxes);\n\n // 2. 组装标准 RFC MIME Buffer\n const rawMime = await buildRawMimeMessage(options, from);\n\n // 3. 追加至草稿箱,打上 \\Draft 与 \\Seen 标记\n await client.append(draftsPath, rawMime, [\"\\\\Draft\", \"\\\\Seen\"]);\n\n return {\n success: true,\n mailbox: draftsPath,\n };\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 极速获取邮箱文件夹状态与未读统计看板\n *\n * @param mailboxAlias 可选指定文件夹别名或物理路径,缺省时查询全部可用文件夹\n * @returns 邮箱状态看板概览报告\n */\n async getMailboxStatus(mailboxAlias?: string): Promise<MailboxStatusReport> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const allMailboxes = await client.list();\n\n // 1. 如果指定了具体文件夹(如 \"INBOX\", \"drafts\" 等),解析别名并只查该文件夹\n if (mailboxAlias && mailboxAlias.toUpperCase() !== \"ALL\") {\n const resolvedPath = resolveSpecialMailbox(mailboxAlias, allMailboxes);\n const status = await client.status(resolvedPath, {\n messages: true,\n unseen: true,\n recent: true,\n });\n\n const item: MailboxStatus = {\n mailbox: resolvedPath,\n total: status.messages || 0,\n unseen: status.unseen || 0,\n recent: status.recent || 0,\n };\n\n return {\n mailboxes: [item],\n totalUnseen: item.unseen,\n totalMessages: item.total,\n };\n }\n\n // 2. 缺省或 ALL 时,并发管道化统计所有物理邮箱状态\n const statusPromises = allMailboxes.map(async (box) => {\n try {\n const status = await client.status(box.path, {\n messages: true,\n unseen: true,\n recent: true,\n });\n\n return {\n mailbox: box.path,\n total: status.messages || 0,\n unseen: status.unseen || 0,\n recent: status.recent || 0,\n };\n } catch {\n // 部分特殊目录可能不支持 STATUS,静默降级为 0\n return {\n mailbox: box.path,\n total: 0,\n unseen: 0,\n recent: 0,\n };\n }\n });\n\n const items = await Promise.all(statusPromises);\n let totalUnseen = 0;\n let totalMessages = 0;\n\n for (const item of items) {\n totalUnseen += item.unseen;\n totalMessages += item.total;\n }\n\n return {\n mailboxes: items,\n totalUnseen,\n totalMessages,\n };\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 将邮件 UID 或 UID 列表格式化为 IMAP SequenceSet 字符串并执行有效性校验\n *\n * @param uids 单个 UID 或 UID 数组\n * @returns 规整后的 IMAP 查询范围字符串与计数\n * @throws Error 当未提供任何有效 UID 时\n */\n private formatUidRange(uids: number | number[]): { range: string; count: number } {\n const list = Array.isArray(uids) ? uids : [uids];\n const valid = list.filter((u) => typeof u === \"number\" && !isNaN(u) && u > 0);\n if (valid.length === 0) {\n throw new Error(\"请提供至少一个有效的邮件 UID 标识符\");\n }\n const sorted = Array.from(new Set(valid)).sort((a, b) => a - b);\n return {\n range: sorted.join(\",\"),\n count: sorted.length,\n };\n }\n\n /**\n * 修改邮件的已读/未读状态标记 (\\Seen)\n *\n * @param uids 单个邮件 UID 或 UID 列表\n * @param read 是否标记为已读(true 为已读,false 为未读,默认 true)\n * @param mailbox 所在邮箱文件夹别名或物理路径,默认 INBOX\n * @returns 状态流转操作结果\n */\n async markEmailRead(\n uids: number | number[],\n read = true,\n mailbox = \"INBOX\"\n ): Promise<MarkEmailReadResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const resolvedMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(resolvedMailbox);\n try {\n const { range, count } = this.formatUidRange(uids);\n if (read) {\n await client.messageFlagsAdd(range, [\"\\\\Seen\"], { uid: true });\n } else {\n await client.messageFlagsRemove(range, [\"\\\\Seen\"], { uid: true });\n }\n\n return {\n success: true,\n count,\n read,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 修改邮件的星标/置顶标记 (\\Flagged)\n *\n * @param uids 单个邮件 UID 或 UID 列表\n * @param flagged 是否设置星标(true 为星标,false 为取消星标,默认 true)\n * @param mailbox 所在邮箱文件夹别名或物理路径,默认 INBOX\n * @returns 星标设置操作结果\n */\n async flagEmail(\n uids: number | number[],\n flagged = true,\n mailbox = \"INBOX\"\n ): Promise<FlagEmailResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const resolvedMailbox = resolveSpecialMailbox(mailbox, mailboxes);\n\n const lock = await client.getMailboxLock(resolvedMailbox);\n try {\n const { range, count } = this.formatUidRange(uids);\n if (flagged) {\n await client.messageFlagsAdd(range, [\"\\\\Flagged\"], { uid: true });\n } else {\n await client.messageFlagsRemove(range, [\"\\\\Flagged\"], { uid: true });\n }\n\n return {\n success: true,\n count,\n flagged,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n\n /**\n * 将邮件跨文件夹移动或转移至回收站进行安全软删除(彻底杜绝物理硬删除 EXPUNGE)\n *\n * @param uids 单个邮件 UID 或 UID 列表\n * @param targetMailbox 目标邮箱文件夹别名或物理路径(如 trash, archive, INBOX)\n * @param sourceMailbox 源邮箱文件夹别名或物理路径,默认 INBOX\n * @returns 移动结果,包含实际物理源路径与目标路径\n */\n async moveEmail(\n uids: number | number[],\n targetMailbox: string,\n sourceMailbox = \"INBOX\"\n ): Promise<MoveEmailResult> {\n const client = this.createClient();\n await client.connect();\n\n try {\n const mailboxes = await client.list();\n const resolvedSource = resolveSpecialMailbox(sourceMailbox, mailboxes);\n const resolvedTarget = resolveSpecialMailbox(targetMailbox, mailboxes);\n\n const lock = await client.getMailboxLock(resolvedSource);\n try {\n const { range, count } = this.formatUidRange(uids);\n await client.messageMove(range, resolvedTarget, { uid: true });\n\n return {\n success: true,\n count,\n sourceMailbox: resolvedSource,\n targetMailbox: resolvedTarget,\n };\n } finally {\n lock.release();\n }\n } finally {\n await client.logout().catch(() => {});\n }\n }\n}\n\nexport const imapService = new ImapService();\n\n\n","/**\n * 特殊用途邮箱目录别名解析与 MIME 载荷构造\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport nodemailer from \"nodemailer\";\nimport type { SendEmailOptions } from \"../types/index.js\";\nimport { validateOutboundAttachmentPath } from \"./attachment-sandbox.js\";\n\n/**\n * 远程邮箱元数据项\n */\nexport interface MailboxItem {\n /** 物理邮箱路径,如 INBOX, [Gmail]/Drafts, 草稿箱 */\n path: string;\n /** 邮箱显示名称 */\n name?: string;\n /** RFC 6154 Special-Use 标志,如 \\Drafts, \\Trash, \\Sent, \\Inbox */\n specialUse?: string;\n}\n\n/**\n * 将逻辑别名(如 drafts, trash, sent, inbox)映射为当前邮箱服务商的物理路径\n *\n * @param logicalAlias 逻辑别名或自定义目录名\n * @param availableMailboxes 服务端返回的物理邮箱列表\n * @returns 解析后的物理邮箱路径\n */\nexport function resolveSpecialMailbox(\n logicalAlias: string,\n availableMailboxes: Array<MailboxItem | string> = []\n): string {\n const normalized = (logicalAlias || \"\").trim().toLowerCase();\n\n // 统一规整为 MailboxItem 标准模型\n const items: MailboxItem[] = availableMailboxes.map((m) => {\n if (typeof m === \"string\") {\n return { path: m, name: m };\n }\n return {\n path: m.path || \"\",\n name: m.name,\n specialUse: m.specialUse,\n };\n });\n\n // 1. 收件箱 (INBOX) 别名映射\n if (normalized === \"inbox\" || normalized === \"收件箱\") {\n const found = items.find(\n (m) =>\n m.specialUse?.toLowerCase() === \"\\\\inbox\" ||\n m.path?.toUpperCase() === \"INBOX\" ||\n m.name?.toUpperCase() === \"INBOX\"\n );\n return found ? found.path : \"INBOX\";\n }\n\n // 2. 草稿箱 (Drafts) 别名映射\n if (\n normalized === \"drafts\" ||\n normalized === \"draft\" ||\n normalized === \"草稿箱\" ||\n normalized === \"草稿\"\n ) {\n const bySpecialUse = items.find(\n (m) => m.specialUse?.toLowerCase() === \"\\\\drafts\"\n );\n if (bySpecialUse) {\n return bySpecialUse.path;\n }\n\n const byName = items.find((m) => {\n const p = m.path.toLowerCase();\n const n = (m.name || \"\").toLowerCase();\n return (\n p === \"drafts\" ||\n p === \"草稿箱\" ||\n p.endsWith(\"/drafts\") ||\n n === \"drafts\" ||\n n === \"草稿箱\"\n );\n });\n if (byName) {\n return byName.path;\n }\n\n return \"Drafts\";\n }\n\n // 3. 回收站 (Trash) 别名映射\n if (\n normalized === \"trash\" ||\n normalized === \"bin\" ||\n normalized === \"deleted\" ||\n normalized === \"已删除\" ||\n normalized === \"回收站\" ||\n normalized === \"废件箱\"\n ) {\n const bySpecialUse = items.find(\n (m) => m.specialUse?.toLowerCase() === \"\\\\trash\"\n );\n if (bySpecialUse) {\n return bySpecialUse.path;\n }\n\n const byName = items.find((m) => {\n const p = m.path.toLowerCase();\n const n = (m.name || \"\").toLowerCase();\n return (\n p === \"trash\" ||\n p === \"deleted messages\" ||\n p === \"已删除\" ||\n p === \"回收站\" ||\n p.endsWith(\"/trash\") ||\n n === \"trash\" ||\n n === \"已删除\" ||\n n === \"回收站\"\n );\n });\n if (byName) {\n return byName.path;\n }\n\n return \"Trash\";\n }\n\n // 4. 已发送 (Sent) 别名映射\n if (\n normalized === \"sent\" ||\n normalized === \"已发送\" ||\n normalized === \"sent messages\"\n ) {\n const bySpecialUse = items.find(\n (m) => m.specialUse?.toLowerCase() === \"\\\\sent\"\n );\n if (bySpecialUse) {\n return bySpecialUse.path;\n }\n\n const byName = items.find((m) => {\n const p = m.path.toLowerCase();\n const n = (m.name || \"\").toLowerCase();\n return (\n p === \"sent\" ||\n p === \"sent messages\" ||\n p === \"已发送\" ||\n p.endsWith(\"/sent mail\") ||\n p.endsWith(\"/sent\") ||\n n === \"sent\" ||\n n === \"已发送\"\n );\n });\n if (byName) {\n return byName.path;\n }\n\n return \"Sent\";\n }\n\n // 5. 尝试精确与不区分大小写匹配物理路径\n const exactMatch = items.find(\n (m) =>\n m.path.toLowerCase() === normalized ||\n (m.name && m.name.toLowerCase() === normalized)\n );\n if (exactMatch) {\n return exactMatch.path;\n }\n\n return logicalAlias;\n}\n\n/**\n * 使用 Nodemailer 纯内存流式传输器构建标准 RFC 822 MIME 数据 Buffer\n *\n * @param options 发信选项载荷\n * @param from 发件人地址\n * @returns 编译后的二进制 Buffer\n */\nexport async function buildRawMimeMessage(\n options: SendEmailOptions,\n from: string\n): Promise<Buffer> {\n const transport = nodemailer.createTransport({\n streamTransport: true,\n buffer: true,\n });\n\n let safeAttachments = options.attachments;\n if (options.attachments && options.attachments.length > 0) {\n safeAttachments = options.attachments.map((att) => {\n if (att.path) {\n const validated = validateOutboundAttachmentPath(att.path);\n return { ...att, path: validated };\n }\n return att;\n });\n }\n\n const mailOptions = {\n from,\n to: Array.isArray(options.to) ? options.to.join(\", \") : options.to,\n cc: options.cc\n ? Array.isArray(options.cc)\n ? options.cc.join(\", \")\n : options.cc\n : undefined,\n bcc: options.bcc\n ? Array.isArray(options.bcc)\n ? options.bcc.join(\", \")\n : options.bcc\n : undefined,\n subject: options.subject,\n text: options.text,\n html: options.html,\n attachments: safeAttachments,\n inReplyTo: options.inReplyTo,\n references: options.references,\n };\n\n const info = await transport.sendMail(mailOptions);\n return info.message as Buffer;\n}\n\n/**\n * 净化邮件正文文本并提取 150 字符 Preview 预览摘要\n *\n * @param raw 原始正文文本或 HTML 字符串或 Buffer\n * @param maxLength 最大摘要字数(默认 150 字符)\n * @returns 净化后的纯文本预览摘要\n */\nexport function extractPreviewSnippet(\n raw: string | Buffer | undefined,\n maxLength = 150\n): string {\n if (!raw) return \"\";\n let text = typeof raw === \"string\" ? raw : raw.toString(\"utf-8\");\n\n // 1. 去除 style 与 script 标签及其内部脚本/样式内容\n text = text.replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, \"\");\n text = text.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, \"\");\n\n // 2. 去除所有 HTML 结构标签\n text = text.replace(/<[^>]+>/g, \" \");\n\n // 3. 常见 HTML 实体字符还原解码\n text = text\n .replace(/&nbsp;/gi, \" \")\n .replace(/&amp;/gi, \"&\")\n .replace(/&lt;/gi, \"<\")\n .replace(/&gt;/gi, \">\")\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\");\n\n // 4. 压缩换行与多余空白符,保证 Preview 纯净单行紧凑\n const cleaned = text.replace(/\\s+/g, \" \").trim();\n if (cleaned.length <= maxLength) {\n return cleaned;\n }\n return cleaned.slice(0, maxLength) + \"...\";\n}\n\n/**\n * 从 IMAP fetch 的 bodyParts 集合或 raw source 提取正文文本内容\n *\n * @param bodyParts 可选的 Map 形式的 bodyParts\n * @param source 可选的 raw source Buffer\n * @returns 提取的文本字符串\n */\nexport function parseBodyFromRawOrParts(\n bodyParts?: Map<string, Buffer>,\n source?: Buffer\n): string {\n // 1. 优先尝试从 bodyParts 获取 TEXT 或第一正文分块\n if (bodyParts) {\n const textPart = bodyParts.get(\"TEXT\") || bodyParts.get(\"1\");\n if (textPart) {\n return textPart.toString(\"utf-8\");\n }\n }\n\n // 2. 回退从 source 剥离邮件头提取正文前缀\n if (source) {\n const raw = source.toString(\"utf-8\");\n const headerSplit = raw.indexOf(\"\\r\\n\\r\\n\");\n if (headerSplit !== -1) {\n return raw.slice(headerSplit + 4);\n }\n const lfSplit = raw.indexOf(\"\\n\\n\");\n if (lfSplit !== -1) {\n return raw.slice(lfSplit + 2);\n }\n }\n\n return \"\";\n}\n\n","/**\n * 附件受管沙箱存储服务,提供目录隔离、文件名净化与防路径穿越校验\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * 获取当前受管附件沙箱的物理根目录\n *\n * 优先使用环境变量 MCP_ATTACHMENT_DIR,未配置时回退至系统临时目录下的独立隔离沙箱。\n *\n * @returns 沙箱根目录物理绝对路径\n */\nexport function getAttachmentSandboxDir(): string {\n const customDir = process.env.MCP_ATTACHMENT_DIR;\n if (customDir && customDir.trim().length > 0) {\n return path.resolve(customDir.trim());\n }\n return path.resolve(os.tmpdir(), \"mcp-email-attachments\");\n}\n\n/**\n * 严格净化原始附件文件名,剔除路径分隔符与危险字符\n *\n * @param rawName 原始附件文件名\n * @returns 净化后的安全纯文件名\n * @throws Error 当文件名包含恶意路径逃逸特征时\n */\nexport function sanitizeFileName(rawName: string): string {\n if (!rawName || typeof rawName !== \"string\") {\n return `attachment-${Date.now()}`;\n }\n\n // 1. 深度检测显式路径穿越标记与空字节逃逸\n if (rawName.includes(\"..\") || rawName.includes(\"\\0\")) {\n throw new Error(`拒绝处理:检测到非法路径穿越文件名 \"${rawName}\"`);\n }\n\n // 2. 剥离可能存在的路径前缀,仅保留基名(兼容正反斜杠)\n const normalized = rawName.replace(/\\\\/g, \"/\");\n let cleanName = path.posix.basename(normalized);\n\n // 3. 过滤系统保留控制字符与危险字符\n cleanName = cleanName.replace(/[\\x00-\\x1f\\x7f<>:\"/\\\\|?*]/g, \"_\").trim();\n\n // 4. 若过滤后文件名为空或仅有点号,回退安全默认名称\n if (!cleanName || cleanName === \".\" || cleanName === \"..\") {\n cleanName = `attachment-${Date.now()}`;\n }\n\n return cleanName;\n}\n\n/**\n * 将附件二进制数据保存至受管沙箱物理目录\n *\n * @param rawFileName 原始文件名\n * @param content 二进制内容 Buffer 或 Uint8Array\n * @param customSandboxDir 可选的自定义沙箱目录(供测试与特定场景注入)\n * @param uid 可选的邮件 UID 标识,用于按邮件分层子目录隔离防同名覆盖\n * @returns 落盘结果信息,包含物理绝对路径与 file:/// 直达 URI\n * @throws Error 当目标路径试图越界逃逸沙箱根目录时\n */\nexport async function saveAttachmentToSandbox(\n rawFileName: string,\n content: Buffer | Uint8Array,\n customSandboxDir?: string,\n uid?: number | string\n): Promise<{ filePath: string; fileUrl: string; filename: string; size: number }> {\n // 1. 解析沙箱绝对根路径并确保目录存在\n const sandboxDir = path.resolve(customSandboxDir || getAttachmentSandboxDir());\n const targetDir = uid !== undefined ? path.join(sandboxDir, String(uid)) : sandboxDir;\n await fs.mkdir(targetDir, { recursive: true });\n\n // 2. 净化文件名\n const safeFileName = sanitizeFileName(rawFileName);\n\n // 3. 构建物理目标路径并进行沙箱边界双重校验\n const targetPath = path.resolve(targetDir, safeFileName);\n const relative = path.relative(sandboxDir, targetPath);\n\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`安全防御触发:目标路径 \"${targetPath}\" 越界逃逸沙箱根目录 \"${sandboxDir}\"`);\n }\n\n // 4. 二进制写入落盘\n await fs.writeFile(targetPath, content);\n\n // 5. 生成标准 file:/// 协议直达链接\n const fileUrl = pathToFileURL(targetPath).toString();\n\n return {\n filePath: targetPath,\n fileUrl,\n filename: safeFileName,\n size: content.byteLength,\n };\n}\n\n/**\n * 校验待外发本地附件路径的安全性,防止敏感文件外发泄露\n *\n * 严格限制仅允许读取受管沙箱目录 (MCP_ATTACHMENT_DIR) 或当前工作区目录下的文件,\n * 严禁越界读取操作系统敏感文件(如 /etc/passwd、id_rsa)及环境变量配置文件 (.env*)。\n *\n * @param candidatePath 候选本地文件路径\n * @returns 规整后的绝对物理路径\n * @throws Error 当路径非法、不存在或超出安全白名单范围时\n */\nexport function validateOutboundAttachmentPath(candidatePath: string): string {\n if (!candidatePath || typeof candidatePath !== \"string\") {\n throw new Error(\"附件路径必须为有效的非空字符串\");\n }\n\n // 1. 拦截空字节注入\n if (candidatePath.includes(\"\\0\")) {\n throw new Error(\"非法附件路径:检测到空字节注入\");\n }\n\n const resolvedPath = path.resolve(candidatePath);\n const baseName = path.basename(resolvedPath).toLowerCase();\n\n // 2. 严格拦截关键敏感凭据与配置文件\n if (\n baseName.startsWith(\".env\") ||\n baseName === \"id_rsa\" ||\n baseName === \"id_ed25519\" ||\n baseName.endsWith(\".pem\") ||\n baseName.endsWith(\".key\") ||\n baseName === \"shadow\" ||\n baseName === \"passwd\" ||\n baseName === \"sam\" ||\n baseName === \"system\"\n ) {\n throw new Error(`安全拦截:严禁外发系统关键敏感凭据文件 \"${baseName}\"`);\n }\n\n // 3. 白名单根目录校验:受管沙箱目录或当前运行工作区目录\n const sandboxDir = getAttachmentSandboxDir();\n const cwdDir = process.cwd();\n\n const relSandbox = path.relative(sandboxDir, resolvedPath);\n const inSandbox = !relSandbox.startsWith(\"..\") && !path.isAbsolute(relSandbox);\n\n const relCwd = path.relative(cwdDir, resolvedPath);\n const inCwd = !relCwd.startsWith(\"..\") && !path.isAbsolute(relCwd);\n\n if (!inSandbox && !inCwd) {\n throw new Error(\n `安全拦截:待外发附件路径 \"${candidatePath}\" 超出允许的安全目录边界(仅允许当前工作区或沙箱附件目录)`\n );\n }\n\n return resolvedPath;\n}\n","/**\n * 邮件正文提纯清洗、轻量 Markdown 转换与 30KB 安全截断\n *\n * @author Ateng\n * @since 2026-10-08\n */\n\n/** 邮件正文最大允许字节数 (30KB) */\nexport const MAX_EMAIL_BODY_BYTES = 30 * 1024;\n\n/** 超长正文安全截断提示声明 */\nexport const TRUNCATION_NOTICE = \"\\n\\n[提示: 邮件正文已超过 30KB 安全阈值,已执行截断保护]\";\n\n/**\n * 将 HTML 富文本清洗转换为结构清晰的轻量 Markdown 或纯文本\n *\n * @param html 原始 HTML 字符串\n * @returns 转换后的 Markdown/纯文本\n */\nexport function htmlToMarkdown(html: string): string {\n if (!html) return \"\";\n\n let text = html;\n\n // 1. 去除头部结构与无意义样式、脚本\n text = text.replace(/<head[^>]*>[\\s\\S]*?<\\/head>/gi, \"\");\n text = text.replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, \"\");\n text = text.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, \"\");\n\n // 2. 转换常见排版与语义标签为 Markdown 格式\n text = text.replace(/<h1\\b[^>]*>([\\s\\S]*?)<\\/h1>/gi, \"\\n# $1\\n\");\n text = text.replace(/<h2\\b[^>]*>([\\s\\S]*?)<\\/h2>/gi, \"\\n## $1\\n\");\n text = text.replace(/<h3\\b[^>]*>([\\s\\S]*?)<\\/h3>/gi, \"\\n### $1\\n\");\n text = text.replace(/<h4\\b[^>]*>([\\s\\S]*?)<\\/h4>/gi, \"\\n#### $1\\n\");\n text = text.replace(/<h5\\b[^>]*>([\\s\\S]*?)<\\/h5>/gi, \"\\n##### $1\\n\");\n text = text.replace(/<h6\\b[^>]*>([\\s\\S]*?)<\\/h6>/gi, \"\\n###### $1\\n\");\n\n text = text.replace(/<(b|strong)\\b[^>]*>([\\s\\S]*?)<\\/\\1>/gi, \"**$2**\");\n text = text.replace(/<(i|em)\\b[^>]*>([\\s\\S]*?)<\\/\\1>/gi, \"*$2*\");\n text = text.replace(/<a\\b[^>]*href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi, \"[$2]($1)\");\n\n text = text.replace(/<li\\b[^>]*>([\\s\\S]*?)<\\/li>/gi, \"\\n- $1\");\n text = text.replace(/<hr\\b[^>]*\\/?>/gi, \"\\n---\\n\");\n text = text.replace(/<br\\b[^>]*\\/?>/gi, \"\\n\");\n text = text.replace(/<\\/(p|div|tr)>/gi, \"\\n\");\n\n\n // 3. 剥离剩余所有 HTML 标签\n text = text.replace(/<[^>]+>/g, \"\");\n\n // 4. 常见 HTML 实体还原\n text = text\n .replace(/&nbsp;/gi, \" \")\n .replace(/&amp;/gi, \"&\")\n .replace(/&lt;/gi, \"<\")\n .replace(/&gt;/gi, \">\")\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\");\n\n // 5. 规整空行与行首尾空白\n const lines = text.split(\"\\n\").map((line) => line.trim());\n const cleanLines: string[] = [];\n let prevEmpty = false;\n\n for (const line of lines) {\n if (line.length === 0) {\n if (!prevEmpty) {\n cleanLines.push(\"\");\n prevEmpty = true;\n }\n } else {\n cleanLines.push(line);\n prevEmpty = false;\n }\n }\n\n return cleanLines.join(\"\\n\").trim();\n}\n\n/**\n * 提纯清洗邮件正文并执行 30KB 安全截断\n *\n * @param text 邮件纯文本内容(如有)\n * @param html 邮件 HTML 内容(如有)\n * @returns 提纯后的正文与是否发生截断标识\n */\nexport function purifyEmailBody(\n text?: string,\n html?: string\n): { content: string; truncated: boolean } {\n // 1. 优先使用已转换的 Markdown 或提取的纯文本\n let rawContent = \"\";\n if (html && html.trim().length > 0) {\n rawContent = htmlToMarkdown(html);\n } else if (text && text.trim().length > 0) {\n rawContent = text.trim();\n }\n\n // 2. 检验 UTF-8 字节大小并执行截断\n const byteLength = Buffer.byteLength(rawContent, \"utf-8\");\n\n if (byteLength > MAX_EMAIL_BODY_BYTES) {\n const buffer = Buffer.from(rawContent, \"utf-8\");\n // 安全截取前 MAX_EMAIL_BODY_BYTES 字节,并过滤不完整字符\n const sliced = buffer.subarray(0, MAX_EMAIL_BODY_BYTES);\n const truncatedText = sliced.toString(\"utf-8\");\n\n return {\n content: truncatedText + TRUNCATION_NOTICE,\n truncated: true,\n };\n }\n\n return {\n content: rawContent,\n truncated: false,\n };\n}\n","/**\n * SMTP 邮件外发核心业务服务\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport nodemailer, { type Transporter } from \"nodemailer\";\nimport { config } from \"../config/index.js\";\nimport type { SendEmailOptions, SmtpConfig } from \"../types/index.js\";\nimport { validateOutboundAttachmentPath } from \"./attachment-sandbox.js\";\n\n/**\n * SMTP 传输管理服务\n */\nexport class SmtpService {\n private transporter: Transporter | null = null;\n\n constructor(private readonly smtpConfig?: SmtpConfig) {}\n\n /**\n * 初始化并获取 Nodemailer 传输器单例\n *\n * @returns 初始化的 Transporter 实例\n * @throws Error 当未配置 SMTP 主机或账号时\n */\n private getTransporter(): Transporter {\n if (this.transporter) {\n return this.transporter;\n }\n\n const host = this.smtpConfig?.host || config.MCP_SMTP_HOST;\n const port = this.smtpConfig?.port ?? config.MCP_SMTP_PORT;\n const secure = this.smtpConfig?.secure ?? config.MCP_SMTP_SECURE;\n const user = this.smtpConfig?.user || config.MCP_SMTP_USER;\n const pass = this.smtpConfig?.pass || config.MCP_SMTP_PASS;\n\n if (!host || !user || !pass) {\n throw new Error(\n \"SMTP 配置不完整:请确保已配置 MCP_SMTP_HOST、MCP_SMTP_USER 和 MCP_SMTP_PASS 环境变量\"\n );\n }\n\n this.transporter = nodemailer.createTransport({\n host,\n port,\n secure,\n auth: {\n user,\n pass,\n },\n });\n\n return this.transporter;\n }\n\n /**\n * 发送电子邮件\n *\n * @param options 发送邮件配置与内容选项\n * @returns 发送结果明细,包含 messageId\n * @throws Error 当发送失败时\n */\n async sendEmail(options: SendEmailOptions): Promise<{ messageId: string; accepted: string[] }> {\n // 1. 获取并校验 SMTP 传输客户端\n const client = this.getTransporter();\n\n // 2. 校验外发附件路径安全性(防敏感数据泄露看门狗)\n let safeAttachments = options.attachments;\n if (options.attachments && options.attachments.length > 0) {\n safeAttachments = options.attachments.map((att) => {\n if (att.path) {\n const validated = validateOutboundAttachmentPath(att.path);\n return { ...att, path: validated };\n }\n return att;\n });\n }\n\n // 3. 组装发件人与信件载荷\n const from =\n options.from ||\n this.smtpConfig?.from ||\n this.smtpConfig?.user ||\n config.MCP_SMTP_FROM ||\n config.MCP_SMTP_USER;\n const mailOptions = {\n from,\n to: Array.isArray(options.to) ? options.to.join(\", \") : options.to,\n cc: options.cc ? (Array.isArray(options.cc) ? options.cc.join(\", \") : options.cc) : undefined,\n bcc: options.bcc ? (Array.isArray(options.bcc) ? options.bcc.join(\", \") : options.bcc) : undefined,\n subject: options.subject,\n text: options.text,\n html: options.html,\n attachments: safeAttachments,\n inReplyTo: options.inReplyTo,\n references: options.references,\n };\n\n // 3. 执行外发传输并返回结果\n const info = await client.sendMail(mailOptions);\n return {\n messageId: info.messageId,\n accepted: Array.isArray(info.accepted) ? (info.accepted as string[]) : [],\n };\n }\n\n /**\n * 验证 SMTP 服务的网络与认证联通性\n *\n * @returns 是否连接成功\n */\n async verifyConnection(): Promise<boolean> {\n const client = this.getTransporter();\n await client.verify();\n return true;\n }\n}\n\nexport const smtpService = new SmtpService();\n","/**\n * 多账户连接池与动态路由调度管理器\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport { config } from \"../config/index.js\";\nimport type {\n AccountProfile,\n ConnectionVerifyReport,\n SanitizedAccountProfile,\n} from \"../types/index.js\";\nimport { ImapService } from \"./imap.service.js\";\nimport { SmtpService } from \"./smtp.service.js\";\n\n/**\n * 账户管理与路由调度核心服务\n */\nexport class AccountManager {\n private readonly accounts = new Map<string, AccountProfile>();\n private readonly defaultAccountId: string;\n private readonly smtpPool = new Map<string, SmtpService>();\n private readonly imapPool = new Map<string, ImapService>();\n\n /**\n * 构造账户管理器实例\n *\n * @param accountList 预加载的账户画像列表,缺省为 config.accounts\n * @param defaultId 默认账户标识,缺省为 config.defaultAccountId\n */\n constructor(\n accountList: AccountProfile[] = config.accounts,\n defaultId: string = config.defaultAccountId\n ) {\n accountList.forEach((acc) => {\n this.accounts.set(acc.id, acc);\n });\n this.defaultAccountId = defaultId;\n }\n\n /**\n * 列出所有已配置的账户脱敏元数据(隐藏密码与授权码)\n *\n * @returns 脱敏账户画像列表\n */\n listAccounts(): SanitizedAccountProfile[] {\n const result: SanitizedAccountProfile[] = [];\n\n for (const [id, acc] of this.accounts.entries()) {\n const canSend = Boolean(acc.smtp);\n const canReceive = Boolean(acc.imap);\n const mode = canSend && canReceive ? \"full\" : canSend ? \"send_only\" : \"receive_only\";\n\n result.push({\n id,\n name: acc.name,\n email: acc.email || acc.smtp?.user || acc.imap?.user,\n isDefault: id === this.defaultAccountId,\n mode,\n capabilities: {\n canSend,\n canReceive,\n },\n smtp: acc.smtp\n ? {\n host: acc.smtp.host,\n port: acc.smtp.port,\n secure: acc.smtp.secure,\n user: acc.smtp.user,\n from: acc.smtp.from,\n }\n : undefined,\n imap: acc.imap\n ? {\n host: acc.imap.host,\n port: acc.imap.port,\n secure: acc.imap.secure,\n user: acc.imap.user,\n }\n : undefined,\n });\n }\n\n return result;\n }\n\n /**\n * 获取指定的账户画像,缺省时自动回退至默认账户\n *\n * @param accountId 可选的账户标识\n * @returns 目标账户完整画像\n * @throws Error 当未找到指定或默认账户配置时\n */\n getAccount(accountId?: string): AccountProfile {\n const targetId = accountId || this.defaultAccountId;\n const account = this.accounts.get(targetId);\n\n if (!account) {\n if (accountId) {\n throw new Error(\n `未找到指定标识为 \"${accountId}\" 的邮箱账户配置,请通过 list_accounts 查看可用画像`\n );\n }\n throw new Error(\n `未找到默认邮箱账户配置 (defaultId: \"${this.defaultAccountId}\"),请检查配置`\n );\n }\n\n return account;\n }\n\n /**\n * 根据账户标识路由并获取缓存的 SMTP 服务实例\n *\n * @param accountId 可选账户标识\n * @returns SMTP 服务实例\n */\n getSmtpService(accountId?: string): SmtpService {\n const account = this.getAccount(accountId);\n if (!account.smtp) {\n throw new Error(\n `账户 \"${account.id}\" 未配置 SMTP 外发服务(当前处于纯收信模式)。如需查阅邮件请调用 search_emails 工具;如需外发邮件,请在配置中补充 MCP_SMTP_* 环境变量。`\n );\n }\n\n let service = this.smtpPool.get(account.id);\n if (!service) {\n service = new SmtpService(account.smtp);\n this.smtpPool.set(account.id, service);\n }\n\n return service;\n }\n\n /**\n * 根据账户标识路由并获取缓存的 IMAP 服务实例\n *\n * @param accountId 可选账户标识\n * @returns IMAP 服务实例\n */\n getImapService(accountId?: string): ImapService {\n const account = this.getAccount(accountId);\n if (!account.imap) {\n throw new Error(\n `账户 \"${account.id}\" 未配置 IMAP 查收服务(当前处于纯发信模式)。如需外发邮件请调用 send_email 工具;如需查阅或检索邮件,请在配置中补充 MCP_IMAP_* 环境变量。`\n );\n }\n\n let service = this.imapPool.get(account.id);\n if (!service) {\n service = new ImapService(account.imap);\n this.imapPool.set(account.id, service);\n }\n\n return service;\n }\n\n /**\n * 对指定或默认账户执行网络连通性与认证体检\n *\n * @param accountId 可选账户标识\n * @returns 综合体检诊断报告\n */\n async verifyConnection(accountId?: string): Promise<ConnectionVerifyReport> {\n const account = this.getAccount(accountId);\n\n // 1. SMTP 协议握手与认证体检\n const smtpResult: ConnectionVerifyReport[\"smtp\"] = {\n configured: Boolean(account.smtp),\n success: false,\n host: account.smtp?.host,\n port: account.smtp?.port,\n };\n\n if (account.smtp) {\n try {\n const smtpClient = this.getSmtpService(account.id);\n await smtpClient.verifyConnection();\n smtpResult.success = true;\n } catch (err: unknown) {\n smtpResult.error = err instanceof Error ? err.message : String(err);\n }\n }\n\n // 2. IMAP 协议握手与认证体检\n const imapResult: ConnectionVerifyReport[\"imap\"] = {\n configured: Boolean(account.imap),\n success: false,\n host: account.imap?.host,\n port: account.imap?.port,\n };\n\n if (account.imap) {\n try {\n const imapClient = this.getImapService(account.id);\n await imapClient.verifyConnection();\n imapResult.success = true;\n } catch (err: unknown) {\n imapResult.error = err instanceof Error ? err.message : String(err);\n }\n }\n\n // 3. 综合判断体检结果\n const overallSuccess =\n (!smtpResult.configured || smtpResult.success) &&\n (!imapResult.configured || imapResult.success) &&\n (smtpResult.configured || imapResult.configured);\n\n // 4. 生成人性化综合诊断说明\n let message: string | undefined;\n if (overallSuccess) {\n if (smtpResult.configured && imapResult.configured) {\n message = \"SMTP 与 IMAP 双通道握手与认证体检均通过\";\n } else if (smtpResult.configured) {\n message = \"SMTP 外发通道连通性验证成功(当前账户处于纯发信模式,未配置 IMAP 查收通道)\";\n } else if (imapResult.configured) {\n message = \"IMAP 查收通道连通性验证成功(当前账户处于纯收信模式,未配置 SMTP 外发通道)\";\n }\n } else {\n const failures: string[] = [];\n if (smtpResult.configured && !smtpResult.success) {\n failures.push(`SMTP 验证失败: ${smtpResult.error || \"未知异常\"}`);\n }\n if (imapResult.configured && !imapResult.success) {\n failures.push(`IMAP 验证失败: ${imapResult.error || \"未知异常\"}`);\n }\n if (!smtpResult.configured && !imapResult.configured) {\n failures.push(\"未配置任何 SMTP 或 IMAP 服务参数\");\n }\n message = failures.join(\"; \");\n }\n\n return {\n account: account.id,\n smtp: smtpResult,\n imap: imapResult,\n overallSuccess,\n message,\n };\n }\n}\n\nexport const accountManager = new AccountManager();\n","/**\n * 邮件会话回复与线程关系维护服务\n *\n * @author Ateng\n * @since 2026-10-08\n */\nimport type { AccountProfile } from \"../types/index.js\";\nimport type { ImapService } from \"./imap.service.js\";\nimport type { SmtpService } from \"./smtp.service.js\";\n\n/**\n * 邮件回复入参选项\n */\nexport interface ReplyEmailOptions {\n /** 被回复原邮件的 UID */\n originalUid: number;\n /** 原邮件所在邮箱(默认 INBOX) */\n mailbox?: string;\n /** 纯文本正文内容 */\n text?: string;\n /** HTML 格式正文内容 */\n html?: string;\n /** 是否全员回复(包含原邮件抄送人) */\n replyAll?: boolean;\n /** 附件清单 */\n attachments?: Array<{\n filename: string;\n path?: string;\n content?: string;\n contentType?: string;\n }>;\n}\n\n/**\n * 邮件回复响应结果\n */\nexport interface ReplyEmailResult {\n /** 新发出的邮件 Message-ID */\n messageId: string;\n /** 投递成功的收件地址列表 */\n accepted: string[];\n /** 关联回复原邮件 Message-ID */\n inReplyTo?: string;\n /** 关联会话引用链 Message-ID 集合 */\n references?: string[];\n /** 主收件人地址 */\n to: string;\n /** 抄送地址列表 */\n cc?: string[];\n /** 最终回复邮件主题 */\n subject: string;\n}\n\n/**\n * 从可能包含显示名称的邮箱字符串中提取纯邮箱地址\n *\n * @param input 原始地址字符串,如 \"User <user@example.com>\" 或 \"user@example.com\"\n * @returns 规范化的纯邮箱地址\n */\nexport function extractEmailAddress(input: string): string {\n const match = input.match(/<([^>]+)>/);\n if (match && match[1]) {\n return match[1].trim().toLowerCase();\n }\n return input.trim().toLowerCase();\n}\n\n/**\n * 格式化回复邮件主题,自动规整 Re: 前缀且避免多重重复\n *\n * @param subject 原始邮件主题\n * @returns 规整后的回复邮件主题\n */\nexport function formatReplySubject(subject: string): string {\n const cleanSubject = (subject || \"\").trim();\n if (/^re:\\s*/i.test(cleanSubject)) {\n return cleanSubject;\n }\n return `Re: ${cleanSubject || \"(无主题)\"}`;\n}\n\n/**\n * 执行邮件会话回复逻辑,自动构建 RFC 线程关系与收件人拓扑\n *\n * @param options 回复选项\n * @param account 发送账户画像\n * @param imapService IMAP 查询服务实例\n * @param smtpService SMTP 发送服务实例\n * @returns 最终外发结果\n */\nexport async function replyEmail(\n options: ReplyEmailOptions,\n account: AccountProfile,\n imapService: ImapService,\n smtpService: SmtpService\n): Promise<ReplyEmailResult> {\n // 1. 获取原邮件详情与头信息\n const mailbox = options.mailbox || \"INBOX\";\n const original = await imapService.getEmailDetail(options.originalUid, mailbox);\n\n if (!original) {\n throw new Error(`未找到 UID 为 ${options.originalUid} 的原始邮件`);\n }\n\n // 2. 解析回复主收件人\n const to = original.fromAddress || extractEmailAddress(original.from);\n\n // 3. 构建全员回复 (replyAll) 抄送人列表,自动排除自身与原发件人\n let cc: string[] | undefined;\n if (options.replyAll) {\n const selfAddresses = new Set<string>();\n if (account.email) {\n selfAddresses.add(account.email.toLowerCase());\n }\n if (account.smtp?.user) {\n selfAddresses.add(account.smtp.user.toLowerCase());\n }\n if (account.imap?.user) {\n selfAddresses.add(account.imap.user.toLowerCase());\n }\n if (account.smtp?.from) {\n selfAddresses.add(extractEmailAddress(account.smtp.from));\n }\n\n const allOriginalRecipients = [...(original.to || []), ...(original.cc || [])];\n const ccSet = new Set<string>();\n\n for (const raw of allOriginalRecipients) {\n const email = extractEmailAddress(raw);\n if (email && email !== to && !selfAddresses.has(email)) {\n ccSet.add(email);\n }\n }\n\n if (ccSet.size > 0) {\n cc = Array.from(ccSet);\n }\n }\n\n // 4. 组装会话线程标识 (In-Reply-To & References) 与主题\n const inReplyTo = original.messageId;\n const references: string[] = original.references ? [...original.references] : [];\n if (original.messageId && !references.includes(original.messageId)) {\n references.push(original.messageId);\n }\n\n const subject = formatReplySubject(original.subject);\n\n // 5. 调用 SMTP 服务外发回复邮件\n const sendResult = await smtpService.sendEmail({\n to,\n cc,\n subject,\n text: options.text,\n html: options.html,\n attachments: options.attachments,\n inReplyTo,\n references: references.length > 0 ? references : undefined,\n });\n\n return {\n messageId: sendResult.messageId,\n accepted: sendResult.accepted,\n inReplyTo,\n references: references.length > 0 ? references : undefined,\n to,\n cc,\n subject,\n };\n}\n"],"mappings":"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","names":["z","fs","path","nodemailer","nodemailer","imapService","smtpService","z","smtpService","imapService"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atengk/mcp-server-email",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "生产级 Email Model Context Protocol (MCP) 服务端,支持 SMTP 邮件外发、IMAP 邮箱检索与附件处理,提供 Stdio 与 SSE 双模传输",
5
5
  "type": "module",
6
6
  "publishConfig": {