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 +125 -0
- package/dist/config/email.config.d.ts.map +1 -0
- package/dist/config/email.config.js +117 -0
- package/dist/config/email.config.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +46 -0
- package/dist/server.js.map +1 -0
- package/dist/services/converter.service.d.ts.map +1 -0
- package/dist/services/converter.service.js +175 -0
- package/dist/services/converter.service.js.map +1 -0
- package/dist/services/email.service.d.ts.map +1 -0
- package/dist/services/email.service.js +192 -0
- package/dist/services/email.service.js.map +1 -0
- package/dist/tools/send-email.d.ts.map +1 -0
- package/dist/tools/send-email.js +98 -0
- package/dist/tools/send-email.js.map +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +40 -0
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(/ /g, ' ')
|
|
142
|
+
.replace(/</g, '<')
|
|
143
|
+
.replace(/>/g, '>')
|
|
144
|
+
.replace(/&/g, '&')
|
|
145
|
+
.replace(/"/g, '"')
|
|
146
|
+
.replace(/'/g, "'")
|
|
147
|
+
.replace(/\s+/g, ' ')
|
|
148
|
+
.trim();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Escape HTML special characters
|
|
152
|
+
*/
|
|
153
|
+
escapeHtml(text) {
|
|
154
|
+
const htmlEscapes = {
|
|
155
|
+
'&': '&',
|
|
156
|
+
'<': '<',
|
|
157
|
+
'>': '>',
|
|
158
|
+
'"': '"',
|
|
159
|
+
"'": ''',
|
|
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 @@
|
|
|
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
|
+
}
|