email-doc-sender 1.0.1

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/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Email Doc Sender MCP
2
+
3
+ 一个基于 MCP (Model Context Protocol) 的本地服务器,为 AI 助手提供邮件发送能力。
4
+
5
+ ## 功能特性
6
+
7
+ - 📧 **邮件发送**: 通过 AI 助手发送邮件
8
+ - 📄 **多格式支持**: Markdown、HTML、纯文本、附件
9
+ - 🔒 **安全可靠**: 支持 TLS/SSL 加密传输
10
+ - ⚙️ **灵活配置**: 支持配置文件和环境变量
11
+ - 🤖 **智能判断**: 自动检测内容格式
12
+
13
+ ## 安装
14
+
15
+ ### 方式 1: 全局安装(推荐)
16
+
17
+ ```bash
18
+ npm install -g email-doc-sender
19
+ ```
20
+
21
+ ### 方式 2: 本地安装
22
+
23
+ ```bash
24
+ npm install email-doc-sender
25
+ npx email-doc-sender
26
+ ```
27
+
28
+ ### 从源码安装
29
+
30
+ ```bash
31
+ git clone <repository-url>
32
+ cd email-doc-sender
33
+ npm install
34
+ npm run build
35
+ ```
36
+
37
+ ## 配置
38
+
39
+ 创建配置文件 `~/.email-doc-sender/config.json`:
40
+
41
+ ```json
42
+ {
43
+ "host": "smtp.qq.com",
44
+ "port": 587,
45
+ "secure": false,
46
+ "auth": {
47
+ "user": "your@qq.com",
48
+ "pass": "授权码"
49
+ },
50
+ "from": "your@qq.com"
51
+ }
52
+ ```
53
+
54
+ 或使用环境变量:
55
+ - `EMAIL_SMTP_HOST`
56
+ - `EMAIL_SMTP_PORT`
57
+ - `EMAIL_SMTP_SECURE`
58
+ - `EMAIL_SMTP_USER`
59
+ - `EMAIL_SMTP_PASS`
60
+ - `EMAIL_FROM`
61
+
62
+ ## 邮箱配置示例
63
+
64
+ ### QQ 邮箱
65
+ - 获取授权码:设置 → 账户 → POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 → 生成授权码
66
+
67
+ ### 163 邮箱
68
+ - 使用 SMTP 端口 465,secure: true
69
+
70
+ ### Gmail
71
+ - 需要启用[应用专用密码](https://support.google.com/accounts/answer/185833)
72
+
73
+ ## Claude Desktop 配置
74
+
75
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
76
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "email-doc-sender": {
82
+ "command": "node",
83
+ "args": ["C:/Users/yourname/AppData/Roaming/npm/email-doc-sender/dist/index.js"]
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ Windows 路径示例:
90
+ ```json
91
+ "args": ["C:\Users\yourname\AppData\Roaming\npm\node_modules\email-doc-sender\dist\index.js"]
92
+ ```
93
+
94
+ ## 使用示例
95
+
96
+ 配置完成后重启 Claude Desktop,然后:
97
+
98
+ ```
99
+ # 发送文字
100
+ 请把这段文字发送到 xxx@qq.com
101
+
102
+ # 发送文件
103
+ 请把 README.md 作为附件发送到 xxx@qq.com
104
+
105
+ # 发送 Markdown
106
+ 请把项目总结发送到 xxx@qq.com
107
+ ```
108
+
109
+ ## 故障排查
110
+
111
+ - **认证失败**: 检查是否使用授权码,确认 SMTP 服务已开启
112
+ - **连接超时**: 检查网络和 SMTP 配置
113
+ - **配置不生效**: 环境变量优先级高于配置文件
114
+
115
+ ## 开发
116
+
117
+ ```bash
118
+ npm run dev # 开发模式
119
+ npm run build # 构建
120
+ npm test # 测试
121
+ ```
122
+
123
+ ## 许可证
124
+
125
+ MIT
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.config.d.ts","sourceRoot":"","sources":["../../src/config/email.config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAevE,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAA4B;gBAE9B,UAAU,CAAC,EAAE,MAAM;IAIzB,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAgDlC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,gBAAgB;IA0BxD,SAAS,IAAI,WAAW;IAOxB,OAAO,CAAC,YAAY;IAKpB,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK7C,SAAS,IAAI,IAAI;CAUlB;AAID,wBAAgB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAKnE"}
@@ -0,0 +1,117 @@
1
+ import { promises as fs } from 'fs';
2
+ import * as path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { homedir } from 'os';
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const PROJECT_ROOT = path.resolve(__dirname, '../..');
7
+ // Config file search paths (in order of priority)
8
+ const CONFIG_PATHS = [
9
+ // User home directory (for npm global installs)
10
+ path.join(homedir(), '.email-doc-sender', 'config.json'),
11
+ // Project directory
12
+ path.join(PROJECT_ROOT, '.email-doc-sender.json'),
13
+ // Legacy project directory (development)
14
+ path.join(PROJECT_ROOT, '.spec-workflow', 'config', 'email-config.json'),
15
+ ];
16
+ export class ConfigManager {
17
+ configPath;
18
+ config = null;
19
+ constructor(configPath) {
20
+ this.configPath = configPath || '';
21
+ }
22
+ async load() {
23
+ let fileConfig = {};
24
+ // Try to load from multiple locations
25
+ const searchPaths = this.configPath ? [this.configPath] : CONFIG_PATHS;
26
+ for (const configPath of searchPaths) {
27
+ try {
28
+ const configContent = await fs.readFile(configPath, 'utf-8');
29
+ fileConfig = JSON.parse(configContent);
30
+ break; // Found config, stop searching
31
+ }
32
+ catch (error) {
33
+ if (error.code !== 'ENOENT') {
34
+ throw new Error(`Invalid config file: ${configPath}`);
35
+ }
36
+ // Continue to next path
37
+ }
38
+ }
39
+ // Environment variables (override file config)
40
+ const envHost = process.env.EMAIL_SMTP_HOST;
41
+ const envPort = process.env.EMAIL_SMTP_PORT;
42
+ const envSecure = process.env.EMAIL_SMTP_SECURE === 'true';
43
+ const envUser = process.env.EMAIL_SMTP_USER;
44
+ const envPass = process.env.EMAIL_SMTP_PASS;
45
+ const envFrom = process.env.EMAIL_FROM;
46
+ // Merge configs (env > file > defaults)
47
+ const mergedConfig = {
48
+ host: envHost ?? fileConfig.host ?? '',
49
+ port: envPort ? parseInt(envPort, 10) : (fileConfig.port ?? 587),
50
+ secure: envSecure ? true : (fileConfig.secure ?? false),
51
+ auth: {
52
+ user: envUser ?? fileConfig.auth?.user ?? '',
53
+ pass: envPass ?? fileConfig.auth?.pass ?? '',
54
+ },
55
+ from: envFrom ?? fileConfig.from ?? '',
56
+ };
57
+ const validation = this.validate(mergedConfig);
58
+ if (!validation.valid) {
59
+ throw new Error('Configuration validation failed:\n' + validation.errors.join('\n'));
60
+ }
61
+ this.config = mergedConfig;
62
+ return mergedConfig;
63
+ }
64
+ validate(config) {
65
+ const errors = [];
66
+ if (!config.host || config.host.trim() === '') {
67
+ errors.push('- Missing required field: host (SMTP server hostname)');
68
+ }
69
+ if (!config.port || config.port < 1 || config.port > 65535) {
70
+ errors.push('- Missing or invalid field: port (must be 1-65535)');
71
+ }
72
+ if (!config.auth?.user || config.auth.user.trim() === '') {
73
+ errors.push('- Missing required field: auth.user (email username)');
74
+ }
75
+ if (!config.auth?.pass || config.auth.pass.trim() === '') {
76
+ errors.push('- Missing required field: auth.pass (email password or app password)');
77
+ }
78
+ if (!config.from || !this.isValidEmail(config.from)) {
79
+ errors.push('- Missing or invalid field: from (sender email address)');
80
+ }
81
+ return { valid: errors.length === 0, errors };
82
+ }
83
+ getConfig() {
84
+ if (!this.config) {
85
+ throw new Error('Configuration not loaded. Call load() first.');
86
+ }
87
+ return this.config;
88
+ }
89
+ isValidEmail(email) {
90
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
91
+ return emailRegex.test(email);
92
+ }
93
+ static maskPassword(password) {
94
+ if (password.length <= 4)
95
+ return '****';
96
+ return password.slice(0, 2) + '*'.repeat(password.length - 4) + password.slice(-2);
97
+ }
98
+ logConfig() {
99
+ if (!this.config)
100
+ return;
101
+ console.log('Email Configuration:');
102
+ console.log(' Host:', this.config.host);
103
+ console.log(' Port:', this.config.port);
104
+ console.log(' Secure:', this.config.secure);
105
+ console.log(' User:', this.config.auth.user);
106
+ console.log(' Password:', ConfigManager.maskPassword(this.config.auth.pass));
107
+ console.log(' From:', this.config.from);
108
+ }
109
+ }
110
+ let configManager = null;
111
+ export function getConfigManager(configPath) {
112
+ if (!configManager) {
113
+ configManager = new ConfigManager(configPath);
114
+ }
115
+ return configManager;
116
+ }
117
+ //# sourceMappingURL=email.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.config.js","sourceRoot":"","sources":["../../src/config/email.config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,89 @@
1
+ import { createServer, startServer } from './server.js';
2
+ import { getConfigManager } from './config/email.config.js';
3
+ /**
4
+ * Main entry point for the Email Doc Sender MCP server
5
+ */
6
+ async function main() {
7
+ try {
8
+ // Load and validate configuration
9
+ console.error('Loading email configuration...');
10
+ const configManager = getConfigManager();
11
+ await configManager.load();
12
+ // Log configuration (passwords masked)
13
+ configManager.logConfig();
14
+ // Verify SMTP connection
15
+ console.error('Verifying SMTP connection...');
16
+ const { getEmailService } = await import('./services/email.service.js');
17
+ const emailService = await getEmailService();
18
+ const isConnected = await emailService.verifyConnection();
19
+ if (!isConnected) {
20
+ console.error('Warning: Could not verify SMTP connection. The server will start, but sending emails may fail.');
21
+ }
22
+ else {
23
+ console.error('SMTP connection verified successfully.');
24
+ }
25
+ // Create and start MCP server
26
+ console.error('Starting MCP server...');
27
+ const server = await createServer();
28
+ await startServer(server);
29
+ // Handle graceful shutdown
30
+ setupShutdownHandlers(server);
31
+ }
32
+ catch (error) {
33
+ // Provide helpful error messages for configuration issues
34
+ if (error instanceof Error) {
35
+ if (error.message.includes('Configuration validation failed')) {
36
+ console.error('\n=== Configuration Error ===');
37
+ console.error(error.message);
38
+ console.error('\nPlease fix your configuration and try again.');
39
+ console.error('You can:');
40
+ console.error(' 1. Create .spec-workflow/config/email-config.json');
41
+ console.error(' 2. Set environment variables (EMAIL_SMTP_*)');
42
+ console.error(' 3. See README.md for examples\n');
43
+ }
44
+ else {
45
+ console.error(`\n=== Error Starting Server ===`);
46
+ console.error(`${error.message}\n`);
47
+ }
48
+ }
49
+ else {
50
+ console.error('\n=== Unknown Error ===');
51
+ console.error('An unexpected error occurred while starting the server.\n');
52
+ }
53
+ process.exit(1);
54
+ }
55
+ }
56
+ /**
57
+ * Setup graceful shutdown handlers
58
+ */
59
+ function setupShutdownHandlers(server) {
60
+ const shutdown = async (signal) => {
61
+ console.error(`\nReceived ${signal}, shutting down gracefully...`);
62
+ try {
63
+ // Close server if it has a close method
64
+ if (server && typeof server === 'object' && 'close' in server) {
65
+ await server.close();
66
+ }
67
+ console.error('Server shut down successfully.');
68
+ process.exit(0);
69
+ }
70
+ catch {
71
+ process.exit(1);
72
+ }
73
+ };
74
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
75
+ process.on('SIGINT', () => shutdown('SIGINT'));
76
+ }
77
+ // Handle uncaught errors
78
+ process.on('uncaughtException', (error) => {
79
+ console.error('Uncaught Exception:', error.message);
80
+ process.exit(1);
81
+ });
82
+ process.on('unhandledRejection', (reason) => {
83
+ const error = reason instanceof Error ? reason.message : String(reason);
84
+ console.error('Unhandled Rejection:', error);
85
+ process.exit(1);
86
+ });
87
+ // Start the server
88
+ main();
89
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAoCpD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM/D"}
package/dist/server.js ADDED
@@ -0,0 +1,46 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { ListToolsRequestSchema, CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
+ import { sendEmailTool, handleSendEmail } from './tools/send-email.js';
5
+ /**
6
+ * Create and configure MCP server
7
+ */
8
+ export async function createServer() {
9
+ // Create server instance
10
+ const server = new Server({
11
+ name: 'email-doc-sender',
12
+ version: '1.0.0',
13
+ }, {
14
+ capabilities: {
15
+ tools: {},
16
+ },
17
+ });
18
+ // Register tool list handler
19
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
20
+ return {
21
+ tools: [sendEmailTool],
22
+ };
23
+ });
24
+ // Register tool call handler
25
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
26
+ const { name, arguments: args } = request.params;
27
+ if (name === 'send_email') {
28
+ return handleSendEmail(args ?? {});
29
+ }
30
+ return {
31
+ content: [{ type: 'text', text: `Unknown tool: ${name}` }],
32
+ isError: true,
33
+ };
34
+ });
35
+ return server;
36
+ }
37
+ /**
38
+ * Start the MCP server with stdio transport
39
+ */
40
+ export async function startServer(server) {
41
+ const transport = new StdioServerTransport();
42
+ await server.connect(transport);
43
+ // Log to stderr so it doesn't interfere with MCP communication
44
+ console.error('Email Doc Sender MCP server running on stdio');
45
+ }
46
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,yBAAyB;IACzB,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;QACE,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CACF,CAAC;IAEF,6BAA6B;IAC7B,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QAC1D,OAAO;YACL,KAAK,EAAE,CAAC,aAAa,CAAC;SACvB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAY,EAAE,EAAE;QACrE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAEjD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1B,OAAO,eAAe,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC;YAC1D,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc;IAC9C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,+DAA+D;IAC/D,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converter.service.d.ts","sourceRoot":"","sources":["../../src/services/converter.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEjE;;;GAGG;AACH,qBAAa,iBAAiB;;IAS5B;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAe3F;;OAEG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAUnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAanB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAuBrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAevB;;OAEG;IACH,OAAO,CAAC,UAAU;CAWnB;AAKD;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,CAKxD"}
@@ -0,0 +1,175 @@
1
+ import { marked } from 'marked';
2
+ /**
3
+ * Document converter service
4
+ * Handles conversion between different document formats for email sending
5
+ */
6
+ export class DocumentConverter {
7
+ constructor() {
8
+ // Configure marked for safe HTML rendering
9
+ marked.setOptions({
10
+ breaks: true,
11
+ gfm: true,
12
+ });
13
+ }
14
+ /**
15
+ * Convert document content to email-ready format
16
+ * @param content - The document content to convert
17
+ * @param format - The format of the input content
18
+ * @param filename - Required when format is 'attachment'
19
+ * @returns ConvertedDoc with HTML, text, and optional attachment
20
+ */
21
+ async convert(content, format, filename) {
22
+ switch (format) {
23
+ case 'markdown':
24
+ return this.convertMarkdown(content);
25
+ case 'html':
26
+ return this.convertHtml(content);
27
+ case 'text':
28
+ return this.convertText(content);
29
+ case 'attachment':
30
+ return this.convertAttachment(content, filename);
31
+ default:
32
+ throw new Error(`Unsupported format: ${format}`);
33
+ }
34
+ }
35
+ /**
36
+ * Convert Markdown to HTML
37
+ */
38
+ convertMarkdown(markdown) {
39
+ const html = marked.parse(markdown);
40
+ return {
41
+ html: this.wrapEmailHtml(html),
42
+ text: this.htmlToPlainText(html),
43
+ };
44
+ }
45
+ /**
46
+ * Validate and wrap HTML content
47
+ */
48
+ convertHtml(htmlContent) {
49
+ // Basic HTML validation
50
+ this.validateHtml(htmlContent);
51
+ return {
52
+ html: this.wrapEmailHtml(htmlContent),
53
+ text: this.htmlToPlainText(htmlContent),
54
+ };
55
+ }
56
+ /**
57
+ * Handle plain text content
58
+ */
59
+ convertText(text) {
60
+ // Escape HTML special characters and wrap in pre
61
+ const escapedHtml = this.escapeHtml(text);
62
+ const html = `
63
+ <div style="font-family: monospace; white-space: pre-wrap;">${escapedHtml}</div>
64
+ `;
65
+ return {
66
+ html: this.wrapEmailHtml(html),
67
+ text: text,
68
+ };
69
+ }
70
+ /**
71
+ * Handle attachment format
72
+ */
73
+ convertAttachment(content, filename) {
74
+ if (!filename) {
75
+ throw new Error('filename is required when format is "attachment"');
76
+ }
77
+ // Convert content to Buffer (assumes content is base64 or raw text)
78
+ const buffer = Buffer.from(content, 'base64');
79
+ return {
80
+ html: '',
81
+ text: '',
82
+ attachment: {
83
+ filename,
84
+ content: buffer,
85
+ },
86
+ };
87
+ }
88
+ /**
89
+ * Wrap HTML content in email-friendly container
90
+ */
91
+ wrapEmailHtml(content) {
92
+ return `
93
+ <!DOCTYPE html>
94
+ <html>
95
+ <head>
96
+ <meta charset="UTF-8">
97
+ <style>
98
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px; }
99
+ h1, h2, h3 { margin-top: 1.5em; }
100
+ code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
101
+ pre { background: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; }
102
+ pre code { background: none; padding: 0; }
103
+ blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 20px; color: #666; }
104
+ a { color: #0066cc; }
105
+ </style>
106
+ </head>
107
+ <body>
108
+ ${content}
109
+ </body>
110
+ </html>
111
+ `.trim();
112
+ }
113
+ /**
114
+ * Basic HTML validation
115
+ */
116
+ validateHtml(html) {
117
+ // Check for potentially dangerous content
118
+ const dangerousPatterns = [
119
+ /<script/i,
120
+ /javascript:/i,
121
+ /on\w+\s*=/i, // Event handlers like onclick=
122
+ ];
123
+ for (const pattern of dangerousPatterns) {
124
+ if (pattern.test(html)) {
125
+ throw new Error('HTML content contains potentially dangerous elements');
126
+ }
127
+ }
128
+ // Basic structure check
129
+ if (!html.includes('<') || !html.includes('>')) {
130
+ throw new Error('Invalid HTML format');
131
+ }
132
+ }
133
+ /**
134
+ * Convert HTML to plain text (fallback)
135
+ */
136
+ htmlToPlainText(html) {
137
+ return html
138
+ .replace(/<style[^>]*>.*?<\/style>/gi, '')
139
+ .replace(/<script[^>]*>.*?<\/script>/gi, '')
140
+ .replace(/<[^>]+>/g, '')
141
+ .replace(/&nbsp;/g, ' ')
142
+ .replace(/&lt;/g, '<')
143
+ .replace(/&gt;/g, '>')
144
+ .replace(/&amp;/g, '&')
145
+ .replace(/&quot;/g, '"')
146
+ .replace(/&#39;/g, "'")
147
+ .replace(/\s+/g, ' ')
148
+ .trim();
149
+ }
150
+ /**
151
+ * Escape HTML special characters
152
+ */
153
+ escapeHtml(text) {
154
+ const htmlEscapes = {
155
+ '&': '&amp;',
156
+ '<': '&lt;',
157
+ '>': '&gt;',
158
+ '"': '&quot;',
159
+ "'": '&#39;',
160
+ };
161
+ return text.replace(/[&<>"']/g, (char) => htmlEscapes[char] || char);
162
+ }
163
+ }
164
+ // Singleton instance
165
+ let converter = null;
166
+ /**
167
+ * Get or create the singleton DocumentConverter instance
168
+ */
169
+ export function getDocumentConverter() {
170
+ if (!converter) {
171
+ converter = new DocumentConverter();
172
+ }
173
+ return converter;
174
+ }
175
+ //# sourceMappingURL=converter.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converter.service.js","sourceRoot":"","sources":["../../src/services/converter.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.service.d.ts","sourceRoot":"","sources":["../../src/services/email.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG9F;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW;IAK/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;;;;OAKG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,GAAE,MAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAgD/E;;;;;;OAMG;IACG,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IA2BxF;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAY1C;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAsB3B;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;CAI/C;AAKD;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAO7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -0,0 +1,192 @@
1
+ import nodemailer from 'nodemailer';
2
+ import { ConfigManager } from '../config/email.config.js';
3
+ /**
4
+ * Email sending service
5
+ * Handles SMTP connection and email sending with retry logic
6
+ */
7
+ export class EmailService {
8
+ transporter = null;
9
+ config;
10
+ constructor(config) {
11
+ this.config = config;
12
+ this.createTransporter();
13
+ }
14
+ /**
15
+ * Create nodemailer transporter with SMTP config
16
+ */
17
+ createTransporter() {
18
+ this.transporter = nodemailer.createTransport({
19
+ host: this.config.host,
20
+ port: this.config.port,
21
+ secure: this.config.secure,
22
+ auth: {
23
+ user: this.config.auth.user,
24
+ pass: this.config.auth.pass,
25
+ },
26
+ // Enforce TLS/SSL
27
+ requireTLS: true,
28
+ tls: {
29
+ // Do not fail on invalid certs (for self-signed certs)
30
+ rejectUnauthorized: false,
31
+ },
32
+ });
33
+ }
34
+ /**
35
+ * Send email with retry logic (exponential backoff)
36
+ * @param options - Email sending options
37
+ * @param maxRetries - Maximum number of retry attempts (default: 3)
38
+ * @returns EmailResult with success status and message ID
39
+ */
40
+ async send(options, maxRetries = 3) {
41
+ let lastError = null;
42
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
43
+ try {
44
+ if (!this.transporter) {
45
+ throw new Error('Transporter not initialized');
46
+ }
47
+ const info = await this.transporter.sendMail({
48
+ from: this.config.from,
49
+ to: options.to,
50
+ subject: options.subject,
51
+ html: options.html,
52
+ text: options.text,
53
+ attachments: options.attachments,
54
+ });
55
+ return {
56
+ success: true,
57
+ messageId: info.messageId,
58
+ };
59
+ }
60
+ catch (error) {
61
+ lastError = error;
62
+ // Don't retry on authentication errors
63
+ if (this.isAuthError(error)) {
64
+ return {
65
+ success: false,
66
+ error: 'Authentication failed. Please check your email credentials.',
67
+ };
68
+ }
69
+ // Wait before retry (exponential backoff: 1s, 2s, 4s)
70
+ if (attempt < maxRetries - 1) {
71
+ const delay = Math.pow(2, attempt) * 1000;
72
+ await this.sleep(delay);
73
+ }
74
+ }
75
+ }
76
+ // All retries failed
77
+ return {
78
+ success: false,
79
+ error: this.getSafeErrorMessage(lastError),
80
+ };
81
+ }
82
+ /**
83
+ * Send converted document
84
+ * @param to - Recipient email address
85
+ * @param subject - Email subject
86
+ * @param doc - Converted document
87
+ * @returns EmailResult
88
+ */
89
+ async sendDocument(to, subject, doc) {
90
+ const options = {
91
+ to,
92
+ subject,
93
+ };
94
+ // Add html if present
95
+ if (doc.html) {
96
+ options.html = doc.html;
97
+ }
98
+ // Add text if present
99
+ if (doc.text) {
100
+ options.text = doc.text;
101
+ }
102
+ // Add attachments if present
103
+ if (doc.attachment) {
104
+ options.attachments = [{
105
+ filename: doc.attachment.filename,
106
+ content: doc.attachment.content,
107
+ }];
108
+ }
109
+ return this.send(options);
110
+ }
111
+ /**
112
+ * Verify SMTP connection
113
+ * @returns true if connection successful
114
+ */
115
+ async verifyConnection() {
116
+ try {
117
+ if (!this.transporter) {
118
+ return false;
119
+ }
120
+ await this.transporter.verify();
121
+ return true;
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
127
+ /**
128
+ * Check if error is authentication related
129
+ */
130
+ isAuthError(error) {
131
+ const errorMessage = error.message.toLowerCase();
132
+ return errorMessage.includes('auth') ||
133
+ errorMessage.includes('invalid login') ||
134
+ errorMessage.includes('username') ||
135
+ errorMessage.includes('password') ||
136
+ errorMessage.includes('credentials');
137
+ }
138
+ /**
139
+ * Get safe error message (don't expose sensitive info)
140
+ */
141
+ getSafeErrorMessage(error) {
142
+ if (!error) {
143
+ return 'Unknown error occurred';
144
+ }
145
+ const message = error.message.toLowerCase();
146
+ // Check for common error patterns
147
+ if (message.includes('etimedout') || message.includes('timeout')) {
148
+ return 'Connection timeout. Please check your network and SMTP server settings.';
149
+ }
150
+ if (message.includes('econnrefused')) {
151
+ return 'Connection refused. Please check the SMTP host and port.';
152
+ }
153
+ if (message.includes('enotfound')) {
154
+ return 'SMTP server not found. Please check the host address.';
155
+ }
156
+ // Generic error message (don't expose raw error)
157
+ return 'Failed to send email. Please check your configuration and try again.';
158
+ }
159
+ /**
160
+ * Sleep for specified milliseconds
161
+ */
162
+ sleep(ms) {
163
+ return new Promise(resolve => setTimeout(resolve, ms));
164
+ }
165
+ /**
166
+ * Recreate transporter (e.g., after config change)
167
+ */
168
+ recreateTransporter(config) {
169
+ this.config = config;
170
+ this.createTransporter();
171
+ }
172
+ }
173
+ // Singleton instance
174
+ let emailService = null;
175
+ /**
176
+ * Get or create the singleton EmailService instance
177
+ */
178
+ export async function getEmailService() {
179
+ if (!emailService) {
180
+ const configManager = new ConfigManager();
181
+ const config = await configManager.load();
182
+ emailService = new EmailService(config);
183
+ }
184
+ return emailService;
185
+ }
186
+ /**
187
+ * Reset the singleton instance (for testing)
188
+ */
189
+ export function resetEmailService() {
190
+ emailService = null;
191
+ }
192
+ //# sourceMappingURL=email.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.service.js","sourceRoot":"","sources":["../../src/services/email.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-email.d.ts","sourceRoot":"","sources":["../../src/tools/send-email.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI/D,eAAO,MAAM,aAAa,EAAE,IAc3B,CAAC;AA0CF,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IAC9E,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAwCD"}
@@ -0,0 +1,98 @@
1
+ import { getDocumentConverter } from '../services/converter.service.js';
2
+ import { getEmailService } from '../services/email.service.js';
3
+ import { promises as fs } from 'fs';
4
+ import * as path from 'path';
5
+ export const sendEmailTool = {
6
+ name: 'send_email',
7
+ description: 'Send an email. Use filePath for file attachments, content for text/markdown in body.',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ to: { type: 'string', description: 'Recipient email address' },
12
+ subject: { type: 'string', description: 'Email subject line' },
13
+ content: { type: 'string', description: 'Text or markdown content for email body' },
14
+ filePath: { type: 'string', description: 'Path to file to send as attachment' },
15
+ format: { type: 'string', enum: ['markdown', 'html', 'text', 'attachment'], description: 'Format (auto-detected if not specified)' },
16
+ },
17
+ required: ['to', 'subject'],
18
+ },
19
+ };
20
+ function detectFormat(params) {
21
+ if (params.format && typeof params.format === 'string') {
22
+ const validFormats = ['markdown', 'html', 'text', 'attachment'];
23
+ if (validFormats.includes(params.format)) {
24
+ return params.format;
25
+ }
26
+ }
27
+ if (params.filePath && typeof params.filePath === 'string') {
28
+ return 'attachment';
29
+ }
30
+ const content = params.content || '';
31
+ const markdownPatterns = [/^#{1,6}\s+/m, /\*\*.*?\*\*/, /\*.*?\*/, /\[.*?\]\(.*?\)/, /```[\s\S]*?```/, /^[-*+]\s/m, /^\d+\.\s/m];
32
+ for (const pattern of markdownPatterns) {
33
+ if (pattern.test(content))
34
+ return 'markdown';
35
+ }
36
+ if (/<[^>]+>/.test(content))
37
+ return 'html';
38
+ return 'text';
39
+ }
40
+ function getFilename(filePath) {
41
+ return path.basename(filePath);
42
+ }
43
+ function validateParams(params) {
44
+ if (!params.to || typeof params.to !== 'string') {
45
+ return { valid: false, error: 'Missing or invalid field: to' };
46
+ }
47
+ if (!params.subject || typeof params.subject !== 'string') {
48
+ return { valid: false, error: 'Missing or invalid field: subject' };
49
+ }
50
+ if (!params.content && !params.filePath) {
51
+ return { valid: false, error: 'Either content or filePath must be provided' };
52
+ }
53
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
54
+ if (!emailRegex.test(params.to)) {
55
+ return { valid: false, error: 'Invalid email address format' };
56
+ }
57
+ return { valid: true };
58
+ }
59
+ export async function handleSendEmail(params) {
60
+ const validation = validateParams(params);
61
+ if (!validation.valid) {
62
+ return { content: [{ type: 'text', text: `Error: ${validation.error}` }], isError: true };
63
+ }
64
+ const to = params.to;
65
+ const subject = params.subject;
66
+ const format = detectFormat(params);
67
+ try {
68
+ const converter = getDocumentConverter();
69
+ const emailService = await getEmailService();
70
+ let convertedDoc;
71
+ if (params.filePath && typeof params.filePath === 'string') {
72
+ const filePath = params.filePath;
73
+ const filename = getFilename(filePath);
74
+ const fileBuffer = await fs.readFile(filePath);
75
+ const base64Content = fileBuffer.toString('base64');
76
+ convertedDoc = await converter.convert(base64Content, 'attachment', filename);
77
+ }
78
+ else {
79
+ const content = params.content;
80
+ convertedDoc = await converter.convert(content, format);
81
+ }
82
+ const result = await emailService.sendDocument(to, subject, convertedDoc);
83
+ if (result.success) {
84
+ const formatDesc = format === 'attachment' ? 'as attachment' : `as ${format}`;
85
+ return {
86
+ content: [{ type: 'text', text: `Email sent to ${to} ${formatDesc}. ID: ${result.messageId}` }],
87
+ };
88
+ }
89
+ else {
90
+ return { content: [{ type: 'text', text: `Failed: ${result.error}` }], isError: true };
91
+ }
92
+ }
93
+ catch (error) {
94
+ const msg = error instanceof Error ? error.message : 'Unknown error';
95
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
96
+ }
97
+ }
98
+ //# sourceMappingURL=send-email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-email.js","sourceRoot":"","sources":["../../src/tools/send-email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,EAAE,OAAO,CAAC;IAChB,sCAAsC;IACtC,IAAI,EAAE;QACJ,6BAA6B;QAC7B,IAAI,EAAE,MAAM,CAAC;QACb,8CAA8C;QAC9C,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,MAAM,EAAE,SAAS,CAAC;IAClB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,UAAU,CAAC,EAAE;QACX,0BAA0B;QAC1B,QAAQ,EAAE,MAAM,CAAC;QACjB,mCAAmC;QACnC,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,mCAAmC;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "email-doc-sender",
3
+ "version": "1.0.1",
4
+ "description": "MCP server for sending generated documents to email",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "email-doc-sender": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "dev": "tsx watch src/index.ts",
12
+ "build": "tsc",
13
+ "start": "node dist/index.js",
14
+ "test": "vitest",
15
+ "test:coverage": "vitest --coverage"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "email",
21
+ "typescript"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "^1.0.4",
27
+ "marked": "^15.0.4",
28
+ "nodemailer": "^6.9.16"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.10.5",
32
+ "@types/nodemailer": "^6.4.17",
33
+ "tsx": "^4.19.2",
34
+ "typescript": "^5.7.2",
35
+ "vitest": "^2.1.8"
36
+ },
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ }
40
+ }