@miguelarios/email-mcp 0.1.0
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 +44 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +7 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/main.d.ts +4 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +36 -0
- package/dist/main.js.map +1 -0
- package/dist/search.d.ts +15 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +98 -0
- package/dist/search.js.map +1 -0
- package/dist/services/ImapService.d.ts +61 -0
- package/dist/services/ImapService.d.ts.map +1 -0
- package/dist/services/ImapService.js +305 -0
- package/dist/services/ImapService.js.map +1 -0
- package/dist/services/SmtpService.d.ts +27 -0
- package/dist/services/SmtpService.d.ts.map +1 -0
- package/dist/services/SmtpService.js +46 -0
- package/dist/services/SmtpService.js.map +1 -0
- package/dist/tools/emailTools.d.ts +12 -0
- package/dist/tools/emailTools.d.ts.map +1 -0
- package/dist/tools/emailTools.js +334 -0
- package/dist/tools/emailTools.js.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @miguelarios/email-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for email via IMAP/SMTP — read, search, send, and manage emails.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @miguelarios/email-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Environment Variables
|
|
12
|
+
|
|
13
|
+
| Variable | Required | Default | Description |
|
|
14
|
+
|----------|----------|---------|-------------|
|
|
15
|
+
| `IMAP_HOST` | Yes | — | IMAP server hostname |
|
|
16
|
+
| `IMAP_USER` | Yes | — | IMAP username |
|
|
17
|
+
| `IMAP_PASS` | Yes | — | IMAP password |
|
|
18
|
+
| `IMAP_PORT` | No | `993` | IMAP port |
|
|
19
|
+
| `IMAP_SECURE` | No | `true` | Use TLS |
|
|
20
|
+
| `SMTP_HOST` | Yes | — | SMTP server hostname |
|
|
21
|
+
| `SMTP_USER` | Yes | — | SMTP username |
|
|
22
|
+
| `SMTP_PASS` | Yes | — | SMTP password |
|
|
23
|
+
| `SMTP_PORT` | No | `465` | SMTP port |
|
|
24
|
+
| `SMTP_SECURE` | No | `true` | Use TLS |
|
|
25
|
+
| `SMTP_FROM_NAME` | No | — | Display name for outgoing emails |
|
|
26
|
+
|
|
27
|
+
## Tools
|
|
28
|
+
|
|
29
|
+
| Tool | Description |
|
|
30
|
+
|------|-------------|
|
|
31
|
+
| `list_emails` | Search and filter emails by folder, sender, subject, date, flags |
|
|
32
|
+
| `get_email` | Fetch full email by UID — headers, body, attachment metadata |
|
|
33
|
+
| `send_email` | Compose and send via SMTP with attachment support |
|
|
34
|
+
| `move_email` | Move email between folders |
|
|
35
|
+
| `mark_email` | Set/unset flags (read, unread, flagged) |
|
|
36
|
+
| `delete_email` | Move to trash or permanently delete |
|
|
37
|
+
| `list_folders` | List all IMAP folders |
|
|
38
|
+
| `create_folder` | Create an IMAP folder |
|
|
39
|
+
| `download_attachment` | Download attachment by email UID and filename |
|
|
40
|
+
| `get_email_raw` | Export email as .eml |
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":""}
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAOnE,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CA8BpD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAKjD"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { loadEmailConfig } from "@miguelarios/pim-core";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { ImapService } from "./services/ImapService.js";
|
|
6
|
+
import { SmtpService } from "./services/SmtpService.js";
|
|
7
|
+
import { EMAIL_TOOLS, handleEmailTool } from "./tools/emailTools.js";
|
|
8
|
+
export async function createServer() {
|
|
9
|
+
const config = loadEmailConfig();
|
|
10
|
+
const imapService = new ImapService(config);
|
|
11
|
+
const smtpService = new SmtpService(config);
|
|
12
|
+
const server = new Server({ name: "@miguelarios/email-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
13
|
+
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
14
|
+
tools: EMAIL_TOOLS,
|
|
15
|
+
}));
|
|
16
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
17
|
+
const { name, arguments: args } = request.params;
|
|
18
|
+
return handleEmailTool(name, (args ?? {}), imapService, smtpService);
|
|
19
|
+
});
|
|
20
|
+
const handleShutdown = async () => {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
};
|
|
23
|
+
process.on("SIGINT", handleShutdown);
|
|
24
|
+
process.on("SIGTERM", handleShutdown);
|
|
25
|
+
server.onerror = (error) => {
|
|
26
|
+
console.error("[email-mcp] Server error:", error.message);
|
|
27
|
+
};
|
|
28
|
+
return server;
|
|
29
|
+
}
|
|
30
|
+
export async function startServer() {
|
|
31
|
+
const server = await createServer();
|
|
32
|
+
const transport = new StdioServerTransport();
|
|
33
|
+
await server.connect(transport);
|
|
34
|
+
console.error("[email-mcp] Server started on stdio");
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAErE,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,OAAO,EAAE,EACpD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,CAAC;QACtD,KAAK,EAAE,WAAW;KACnB,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,OAAO,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,CAA4B,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAClG,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;QAChC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAEtC,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QACzB,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5D,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses structured search query strings into imapflow-compatible search criteria.
|
|
3
|
+
*
|
|
4
|
+
* Supported prefixes:
|
|
5
|
+
* - from:address → IMAP FROM filter
|
|
6
|
+
* - to:address → IMAP TO filter
|
|
7
|
+
* - subject:text → IMAP SUBJECT filter
|
|
8
|
+
* - is:unread/read/flagged → flag filters
|
|
9
|
+
* - has:attachment → Content-Type header check
|
|
10
|
+
* - since:YYYY-MM-DD → date range start
|
|
11
|
+
* - before:YYYY-MM-DD → date range end
|
|
12
|
+
* - plain text → IMAP BODY search
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseSearchQuery(query: string): Record<string, unknown>;
|
|
15
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiFvE"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses structured search query strings into imapflow-compatible search criteria.
|
|
3
|
+
*
|
|
4
|
+
* Supported prefixes:
|
|
5
|
+
* - from:address → IMAP FROM filter
|
|
6
|
+
* - to:address → IMAP TO filter
|
|
7
|
+
* - subject:text → IMAP SUBJECT filter
|
|
8
|
+
* - is:unread/read/flagged → flag filters
|
|
9
|
+
* - has:attachment → Content-Type header check
|
|
10
|
+
* - since:YYYY-MM-DD → date range start
|
|
11
|
+
* - before:YYYY-MM-DD → date range end
|
|
12
|
+
* - plain text → IMAP BODY search
|
|
13
|
+
*/
|
|
14
|
+
export function parseSearchQuery(query) {
|
|
15
|
+
const trimmed = query.trim();
|
|
16
|
+
if (!trimmed)
|
|
17
|
+
return {};
|
|
18
|
+
const criteria = {};
|
|
19
|
+
const plainParts = [];
|
|
20
|
+
const tokens = trimmed.split(/\s+/);
|
|
21
|
+
let i = 0;
|
|
22
|
+
while (i < tokens.length) {
|
|
23
|
+
const token = tokens[i];
|
|
24
|
+
const colonIndex = token.indexOf(":");
|
|
25
|
+
if (colonIndex > 0) {
|
|
26
|
+
const prefix = token.substring(0, colonIndex).toLowerCase();
|
|
27
|
+
const value = token.substring(colonIndex + 1);
|
|
28
|
+
switch (prefix) {
|
|
29
|
+
case "from":
|
|
30
|
+
criteria.from = value;
|
|
31
|
+
i++;
|
|
32
|
+
break;
|
|
33
|
+
case "to":
|
|
34
|
+
criteria.to = value;
|
|
35
|
+
i++;
|
|
36
|
+
break;
|
|
37
|
+
case "subject": {
|
|
38
|
+
const subjectParts = [value];
|
|
39
|
+
i++;
|
|
40
|
+
while (i < tokens.length && !isPrefix(tokens[i])) {
|
|
41
|
+
subjectParts.push(tokens[i]);
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
criteria.subject = subjectParts.join(" ");
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case "is":
|
|
48
|
+
switch (value.toLowerCase()) {
|
|
49
|
+
case "unread":
|
|
50
|
+
criteria.seen = false;
|
|
51
|
+
break;
|
|
52
|
+
case "read":
|
|
53
|
+
criteria.seen = true;
|
|
54
|
+
break;
|
|
55
|
+
case "flagged":
|
|
56
|
+
criteria.flagged = true;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
i++;
|
|
60
|
+
break;
|
|
61
|
+
case "has":
|
|
62
|
+
if (value.toLowerCase() === "attachment") {
|
|
63
|
+
criteria.header = { "content-type": "multipart/mixed" };
|
|
64
|
+
}
|
|
65
|
+
i++;
|
|
66
|
+
break;
|
|
67
|
+
case "since":
|
|
68
|
+
criteria.since = new Date(value);
|
|
69
|
+
i++;
|
|
70
|
+
break;
|
|
71
|
+
case "before":
|
|
72
|
+
criteria.before = new Date(value);
|
|
73
|
+
i++;
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
plainParts.push(token);
|
|
77
|
+
i++;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
plainParts.push(token);
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (plainParts.length > 0) {
|
|
87
|
+
criteria.body = plainParts.join(" ");
|
|
88
|
+
}
|
|
89
|
+
return criteria;
|
|
90
|
+
}
|
|
91
|
+
const KNOWN_PREFIXES = new Set(["from", "to", "subject", "is", "has", "since", "before"]);
|
|
92
|
+
function isPrefix(token) {
|
|
93
|
+
const colonIndex = token.indexOf(":");
|
|
94
|
+
if (colonIndex <= 0)
|
|
95
|
+
return false;
|
|
96
|
+
return KNOWN_PREFIXES.has(token.substring(0, colonIndex).toLowerCase());
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type EmailConfig } from "@miguelarios/pim-core";
|
|
2
|
+
export interface EmailSummary {
|
|
3
|
+
uid: number;
|
|
4
|
+
messageId: string;
|
|
5
|
+
subject: string;
|
|
6
|
+
from: {
|
|
7
|
+
name?: string;
|
|
8
|
+
address: string;
|
|
9
|
+
};
|
|
10
|
+
to: Array<{
|
|
11
|
+
name?: string;
|
|
12
|
+
address: string;
|
|
13
|
+
}>;
|
|
14
|
+
date: string;
|
|
15
|
+
flags: string[];
|
|
16
|
+
hasAttachments: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface EmailFull extends EmailSummary {
|
|
19
|
+
cc?: Array<{
|
|
20
|
+
name?: string;
|
|
21
|
+
address: string;
|
|
22
|
+
}>;
|
|
23
|
+
textBody?: string;
|
|
24
|
+
htmlBody?: string;
|
|
25
|
+
attachments: Array<{
|
|
26
|
+
filename: string;
|
|
27
|
+
contentType: string;
|
|
28
|
+
size: number;
|
|
29
|
+
partId: string;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
export interface FolderInfo {
|
|
33
|
+
path: string;
|
|
34
|
+
specialUse?: string;
|
|
35
|
+
delimiter: string;
|
|
36
|
+
}
|
|
37
|
+
export interface AttachmentData {
|
|
38
|
+
filename: string;
|
|
39
|
+
contentType: string;
|
|
40
|
+
size: number;
|
|
41
|
+
content: Buffer;
|
|
42
|
+
}
|
|
43
|
+
export interface SearchOptions {
|
|
44
|
+
limit?: number;
|
|
45
|
+
offset?: number;
|
|
46
|
+
}
|
|
47
|
+
export declare class ImapService {
|
|
48
|
+
private config;
|
|
49
|
+
constructor(config: EmailConfig);
|
|
50
|
+
private createClient;
|
|
51
|
+
listFolders(): Promise<FolderInfo[]>;
|
|
52
|
+
searchEmails(folder: string, query: Record<string, unknown>, options?: SearchOptions): Promise<EmailSummary[]>;
|
|
53
|
+
fetchEmail(folder: string, uid: number): Promise<EmailFull>;
|
|
54
|
+
fetchRawEmail(folder: string, uid: number): Promise<string>;
|
|
55
|
+
moveEmails(folder: string, uids: number[], destination: string): Promise<void>;
|
|
56
|
+
markEmails(folder: string, uids: number[], flags: string[], action: "add" | "remove"): Promise<void>;
|
|
57
|
+
deleteEmails(folder: string, uids: number[], permanent?: boolean): Promise<void>;
|
|
58
|
+
createFolder(path: string): Promise<void>;
|
|
59
|
+
downloadAttachment(folder: string, uid: number, partId: string): Promise<AttachmentData>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=ImapService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImapService.d.ts","sourceRoot":"","sources":["../../src/services/ImapService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAqC,MAAM,uBAAuB,CAAC;AAI5F,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,EAAE,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,EAAE,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW;IAI/B,OAAO,CAAC,YAAY;IAad,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAiBpC,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC;IA0DpB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAoD3D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB3D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9E,UAAU,CACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,EAAE,KAAK,GAAG,QAAQ,GACvB,OAAO,CAAC,IAAI,CAAC;IAwBV,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB9E,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYzC,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAoC/F"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { EmailError, ErrorCode, toPimError } from "@miguelarios/pim-core";
|
|
2
|
+
import { ImapFlow } from "imapflow";
|
|
3
|
+
import { simpleParser } from "mailparser";
|
|
4
|
+
export class ImapService {
|
|
5
|
+
config;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
createClient() {
|
|
10
|
+
return new ImapFlow({
|
|
11
|
+
host: this.config.imap.host,
|
|
12
|
+
port: this.config.imap.port,
|
|
13
|
+
secure: this.config.imap.secure,
|
|
14
|
+
auth: {
|
|
15
|
+
user: this.config.imap.user,
|
|
16
|
+
pass: this.config.imap.pass,
|
|
17
|
+
},
|
|
18
|
+
logger: false,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async listFolders() {
|
|
22
|
+
const client = this.createClient();
|
|
23
|
+
try {
|
|
24
|
+
await client.connect();
|
|
25
|
+
const mailboxes = await client.list();
|
|
26
|
+
return mailboxes.map((mb) => ({
|
|
27
|
+
path: mb.path,
|
|
28
|
+
specialUse: mb.specialUse || undefined,
|
|
29
|
+
delimiter: mb.delimiter,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
await client.logout().catch(() => { });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async searchEmails(folder, query, options = {}) {
|
|
40
|
+
const client = this.createClient();
|
|
41
|
+
try {
|
|
42
|
+
await client.connect();
|
|
43
|
+
const lock = await client.getMailboxLock(folder);
|
|
44
|
+
try {
|
|
45
|
+
const searchCriteria = Object.keys(query).length > 0 ? query : { all: true };
|
|
46
|
+
const searchResult = await client.search(searchCriteria, {
|
|
47
|
+
uid: true,
|
|
48
|
+
});
|
|
49
|
+
const uids = searchResult || [];
|
|
50
|
+
if (uids.length === 0)
|
|
51
|
+
return [];
|
|
52
|
+
const offset = options.offset ?? 0;
|
|
53
|
+
const limit = options.limit ?? 50;
|
|
54
|
+
const sliced = uids.slice(offset, offset + limit);
|
|
55
|
+
const summaries = [];
|
|
56
|
+
const uidRange = sliced.join(",");
|
|
57
|
+
for await (const msg of client.fetch(uidRange, {
|
|
58
|
+
envelope: true,
|
|
59
|
+
flags: true,
|
|
60
|
+
bodyStructure: true,
|
|
61
|
+
uid: true,
|
|
62
|
+
})) {
|
|
63
|
+
const envelope = msg.envelope;
|
|
64
|
+
summaries.push({
|
|
65
|
+
uid: msg.uid,
|
|
66
|
+
messageId: envelope.messageId || "",
|
|
67
|
+
subject: envelope.subject || "",
|
|
68
|
+
from: envelope.from?.[0]
|
|
69
|
+
? {
|
|
70
|
+
name: envelope.from[0].name,
|
|
71
|
+
address: envelope.from[0].address || "",
|
|
72
|
+
}
|
|
73
|
+
: { address: "unknown" },
|
|
74
|
+
to: (envelope.to || []).map((a) => ({
|
|
75
|
+
name: a.name,
|
|
76
|
+
address: a.address || "",
|
|
77
|
+
})),
|
|
78
|
+
date: envelope.date?.toISOString() || "",
|
|
79
|
+
flags: [...(msg.flags || [])],
|
|
80
|
+
hasAttachments: hasAttachmentParts(msg.bodyStructure),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return summaries;
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
lock.release();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await client.logout().catch(() => { });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async fetchEmail(folder, uid) {
|
|
97
|
+
const client = this.createClient();
|
|
98
|
+
try {
|
|
99
|
+
await client.connect();
|
|
100
|
+
const lock = await client.getMailboxLock(folder);
|
|
101
|
+
try {
|
|
102
|
+
const fetchResult = await client.fetchOne(String(uid), { source: true }, { uid: true });
|
|
103
|
+
if (!fetchResult || !fetchResult.source) {
|
|
104
|
+
throw new EmailError(`Email UID ${uid} not found`, ErrorCode.EMAIL_NOT_FOUND, uid);
|
|
105
|
+
}
|
|
106
|
+
const parsed = await simpleParser(fetchResult.source);
|
|
107
|
+
return {
|
|
108
|
+
uid,
|
|
109
|
+
messageId: parsed.messageId || "",
|
|
110
|
+
subject: parsed.subject || "",
|
|
111
|
+
from: parsed.from?.value?.[0]
|
|
112
|
+
? {
|
|
113
|
+
name: parsed.from.value[0].name,
|
|
114
|
+
address: parsed.from.value[0].address || "",
|
|
115
|
+
}
|
|
116
|
+
: { address: "unknown" },
|
|
117
|
+
to: (Array.isArray(parsed.to) ? parsed.to : parsed.to ? [parsed.to] : [])
|
|
118
|
+
.flatMap((addr) => addr.value)
|
|
119
|
+
.map((a) => ({ name: a.name, address: a.address || "" })),
|
|
120
|
+
cc: (Array.isArray(parsed.cc) ? parsed.cc : parsed.cc ? [parsed.cc] : [])
|
|
121
|
+
.flatMap((addr) => addr.value)
|
|
122
|
+
.map((a) => ({ name: a.name, address: a.address || "" })) || undefined,
|
|
123
|
+
date: parsed.date?.toISOString() || "",
|
|
124
|
+
flags: [],
|
|
125
|
+
hasAttachments: (parsed.attachments?.length || 0) > 0,
|
|
126
|
+
textBody: parsed.text || undefined,
|
|
127
|
+
htmlBody: parsed.html || undefined,
|
|
128
|
+
attachments: (parsed.attachments || []).map((att, index) => ({
|
|
129
|
+
filename: att.filename || `attachment-${index}`,
|
|
130
|
+
contentType: att.contentType || "application/octet-stream",
|
|
131
|
+
size: att.size || 0,
|
|
132
|
+
partId: String(index + 1),
|
|
133
|
+
})),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
lock.release();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (error instanceof EmailError)
|
|
142
|
+
throw error;
|
|
143
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
await client.logout().catch(() => { });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async fetchRawEmail(folder, uid) {
|
|
150
|
+
const client = this.createClient();
|
|
151
|
+
try {
|
|
152
|
+
await client.connect();
|
|
153
|
+
const lock = await client.getMailboxLock(folder);
|
|
154
|
+
try {
|
|
155
|
+
const fetchResult = await client.fetchOne(String(uid), { source: true }, { uid: true });
|
|
156
|
+
if (!fetchResult || !fetchResult.source) {
|
|
157
|
+
throw new EmailError(`Email UID ${uid} not found`, ErrorCode.EMAIL_NOT_FOUND, uid);
|
|
158
|
+
}
|
|
159
|
+
return fetchResult.source.toString();
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
lock.release();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof EmailError)
|
|
167
|
+
throw error;
|
|
168
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
await client.logout().catch(() => { });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async moveEmails(folder, uids, destination) {
|
|
175
|
+
const client = this.createClient();
|
|
176
|
+
try {
|
|
177
|
+
await client.connect();
|
|
178
|
+
const lock = await client.getMailboxLock(folder);
|
|
179
|
+
try {
|
|
180
|
+
await client.messageMove(uids.join(","), destination, {
|
|
181
|
+
uid: true,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
lock.release();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
await client.logout().catch(() => { });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async markEmails(folder, uids, flags, action) {
|
|
196
|
+
const client = this.createClient();
|
|
197
|
+
try {
|
|
198
|
+
await client.connect();
|
|
199
|
+
const lock = await client.getMailboxLock(folder);
|
|
200
|
+
try {
|
|
201
|
+
const uidRange = uids.join(",");
|
|
202
|
+
if (action === "add") {
|
|
203
|
+
await client.messageFlagsAdd(uidRange, flags, { uid: true });
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
await client.messageFlagsRemove(uidRange, flags, {
|
|
207
|
+
uid: true,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
lock.release();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
await client.logout().catch(() => { });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async deleteEmails(folder, uids, permanent = false) {
|
|
223
|
+
const client = this.createClient();
|
|
224
|
+
try {
|
|
225
|
+
await client.connect();
|
|
226
|
+
const lock = await client.getMailboxLock(folder);
|
|
227
|
+
try {
|
|
228
|
+
const uidRange = uids.join(",");
|
|
229
|
+
if (permanent) {
|
|
230
|
+
await client.messageDelete(uidRange, { uid: true });
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
await client.messageMove(uidRange, "Trash", { uid: true });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
lock.release();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
await client.logout().catch(() => { });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async createFolder(path) {
|
|
248
|
+
const client = this.createClient();
|
|
249
|
+
try {
|
|
250
|
+
await client.connect();
|
|
251
|
+
await client.mailboxCreate(path);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
await client.logout().catch(() => { });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async downloadAttachment(folder, uid, partId) {
|
|
261
|
+
const client = this.createClient();
|
|
262
|
+
try {
|
|
263
|
+
await client.connect();
|
|
264
|
+
const lock = await client.getMailboxLock(folder);
|
|
265
|
+
try {
|
|
266
|
+
const { meta, content } = await client.download(String(uid), partId, { uid: true });
|
|
267
|
+
if (!content) {
|
|
268
|
+
throw new EmailError(`Attachment ${partId} not found for email ${uid}`, ErrorCode.ATTACHMENT_NOT_FOUND, uid);
|
|
269
|
+
}
|
|
270
|
+
const chunks = [];
|
|
271
|
+
for await (const chunk of content) {
|
|
272
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
filename: meta.filename || `attachment-${partId}`,
|
|
276
|
+
contentType: meta.contentType || "application/octet-stream",
|
|
277
|
+
size: meta.expectedSize || Buffer.concat(chunks).length,
|
|
278
|
+
content: Buffer.concat(chunks),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
lock.release();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
if (error instanceof EmailError)
|
|
287
|
+
throw error;
|
|
288
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
await client.logout().catch(() => { });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function hasAttachmentParts(bodyStructure) {
|
|
296
|
+
if (!bodyStructure)
|
|
297
|
+
return false;
|
|
298
|
+
if (bodyStructure.type?.toLowerCase().includes("multipart/mixed"))
|
|
299
|
+
return true;
|
|
300
|
+
if (bodyStructure.childNodes) {
|
|
301
|
+
return bodyStructure.childNodes.some((node) => hasAttachmentParts(node));
|
|
302
|
+
}
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=ImapService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImapService.js","sourceRoot":"","sources":["../../src/services/ImapService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type EmailConfig } from "@miguelarios/pim-core";
|
|
2
|
+
export interface SendEmailOptions {
|
|
3
|
+
to: string[];
|
|
4
|
+
cc?: string[];
|
|
5
|
+
bcc?: string[];
|
|
6
|
+
subject: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
html?: string;
|
|
9
|
+
attachments?: Array<{
|
|
10
|
+
filename: string;
|
|
11
|
+
path?: string;
|
|
12
|
+
content?: string | Buffer;
|
|
13
|
+
contentType?: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export interface SendResult {
|
|
17
|
+
messageId: string;
|
|
18
|
+
accepted: string[];
|
|
19
|
+
rejected: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare class SmtpService {
|
|
22
|
+
private config;
|
|
23
|
+
constructor(config: EmailConfig);
|
|
24
|
+
private createTransporter;
|
|
25
|
+
sendEmail(options: SendEmailOptions): Promise<SendResult>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=SmtpService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmtpService.d.ts","sourceRoot":"","sources":["../../src/services/SmtpService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,uBAAuB,CAAC;AAIrE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW;IAI/B,OAAO,CAAC,iBAAiB;IAYnB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;CA2BhE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { toPimError } from "@miguelarios/pim-core";
|
|
2
|
+
import nodemailer from "nodemailer";
|
|
3
|
+
export class SmtpService {
|
|
4
|
+
config;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
}
|
|
8
|
+
createTransporter() {
|
|
9
|
+
return nodemailer.createTransport({
|
|
10
|
+
host: this.config.smtp.host,
|
|
11
|
+
port: this.config.smtp.port,
|
|
12
|
+
secure: this.config.smtp.secure,
|
|
13
|
+
auth: {
|
|
14
|
+
user: this.config.smtp.user,
|
|
15
|
+
pass: this.config.smtp.pass,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async sendEmail(options) {
|
|
20
|
+
const transporter = this.createTransporter();
|
|
21
|
+
try {
|
|
22
|
+
const from = this.config.fromName
|
|
23
|
+
? `"${this.config.fromName}" <${this.config.smtp.user}>`
|
|
24
|
+
: this.config.smtp.user;
|
|
25
|
+
const info = await transporter.sendMail({
|
|
26
|
+
from,
|
|
27
|
+
to: options.to.join(", "),
|
|
28
|
+
cc: options.cc?.join(", "),
|
|
29
|
+
bcc: options.bcc?.join(", "),
|
|
30
|
+
subject: options.subject,
|
|
31
|
+
text: options.text,
|
|
32
|
+
html: options.html,
|
|
33
|
+
attachments: options.attachments,
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
messageId: info.messageId,
|
|
37
|
+
accepted: info.accepted,
|
|
38
|
+
rejected: info.rejected,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw toPimError(error instanceof Error ? error : new Error(String(error)));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=SmtpService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmtpService.js","sourceRoot":"","sources":["../../src/services/SmtpService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,UAAU,MAAM,YAAY,CAAC;AAwBpC,MAAM,OAAO,WAAW;IACd,MAAM,CAAc;IAE5B,YAAY,MAAmB;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,iBAAiB;QACvB,OAAO,UAAU,CAAC,eAAe,CAAC;YAChC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM;YAC/B,IAAI,EAAE;gBACJ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;gBAC3B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;aAC5B;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAyB;QACvC,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAC/B,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG;gBACxD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YAE1B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC;gBACtC,IAAI;gBACJ,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;gBACzB,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC;gBAC1B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC;gBAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC,CAAC;YAEH,OAAO;gBACL,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,IAAI,CAAC,QAAoB;gBACnC,QAAQ,EAAE,IAAI,CAAC,QAAoB;aACpC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,UAAU,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { ImapService } from "../services/ImapService.js";
|
|
3
|
+
import type { SmtpService } from "../services/SmtpService.js";
|
|
4
|
+
export declare const EMAIL_TOOLS: Tool[];
|
|
5
|
+
export declare function handleEmailTool(name: string, args: Record<string, unknown>, imapService: ImapService, smtpService: SmtpService): Promise<{
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: "text";
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
isError?: boolean;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=emailTools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailTools.d.ts","sourceRoot":"","sources":["../../src/tools/emailTools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,eAAO,MAAM,WAAW,EAAE,IAAI,EAqP7B,CAAC;AAEF,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC;IACT,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,CAoGD"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { toPimError } from "@miguelarios/pim-core";
|
|
2
|
+
import { parseSearchQuery } from "../search.js";
|
|
3
|
+
export const EMAIL_TOOLS = [
|
|
4
|
+
{
|
|
5
|
+
name: "list_emails",
|
|
6
|
+
description: "Search and list emails in a folder. Supports structured query prefixes: from:, to:, subject:, is:unread/read/flagged, has:attachment, since:YYYY-MM-DD, before:YYYY-MM-DD. Plain text searches subject and body. Returns email summaries with UID, subject, sender, date, and flags.",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
folder: {
|
|
11
|
+
type: "string",
|
|
12
|
+
description: "IMAP folder to search. Defaults to INBOX.",
|
|
13
|
+
},
|
|
14
|
+
query: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: 'Search query with optional prefixes. Examples: "from:boss@work.com is:unread", "subject:meeting", "has:attachment". Plain text searches body.',
|
|
17
|
+
},
|
|
18
|
+
limit: {
|
|
19
|
+
type: "number",
|
|
20
|
+
description: "Max results to return. Defaults to 20.",
|
|
21
|
+
},
|
|
22
|
+
offset: {
|
|
23
|
+
type: "number",
|
|
24
|
+
description: "Number of results to skip for pagination. Defaults to 0.",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "get_email",
|
|
31
|
+
description: "Fetch a full email by UID including headers, text/HTML body, and attachment metadata.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
folder: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "IMAP folder containing the email. Defaults to INBOX.",
|
|
38
|
+
},
|
|
39
|
+
uid: {
|
|
40
|
+
type: "number",
|
|
41
|
+
description: "The UID of the email to fetch.",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ["uid"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "send_email",
|
|
49
|
+
description: "Compose and send an email via SMTP. Supports to/cc/bcc, text and HTML body, and file attachments.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
to: {
|
|
54
|
+
type: "array",
|
|
55
|
+
items: { type: "string" },
|
|
56
|
+
description: "Recipient email addresses.",
|
|
57
|
+
},
|
|
58
|
+
cc: {
|
|
59
|
+
type: "array",
|
|
60
|
+
items: { type: "string" },
|
|
61
|
+
description: "CC email addresses.",
|
|
62
|
+
},
|
|
63
|
+
bcc: {
|
|
64
|
+
type: "array",
|
|
65
|
+
items: { type: "string" },
|
|
66
|
+
description: "BCC email addresses.",
|
|
67
|
+
},
|
|
68
|
+
subject: {
|
|
69
|
+
type: "string",
|
|
70
|
+
description: "Email subject line.",
|
|
71
|
+
},
|
|
72
|
+
text: {
|
|
73
|
+
type: "string",
|
|
74
|
+
description: "Plain text body.",
|
|
75
|
+
},
|
|
76
|
+
html: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "HTML body.",
|
|
79
|
+
},
|
|
80
|
+
attachments: {
|
|
81
|
+
type: "array",
|
|
82
|
+
items: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
filename: { type: "string" },
|
|
86
|
+
path: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "File path to attach.",
|
|
89
|
+
},
|
|
90
|
+
content: {
|
|
91
|
+
type: "string",
|
|
92
|
+
description: "String content to attach.",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
required: ["filename"],
|
|
96
|
+
},
|
|
97
|
+
description: "File attachments.",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
required: ["to", "subject"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "move_email",
|
|
105
|
+
description: "Move one or more emails to a different IMAP folder.",
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
folder: {
|
|
110
|
+
type: "string",
|
|
111
|
+
description: "Source IMAP folder. Defaults to INBOX.",
|
|
112
|
+
},
|
|
113
|
+
uids: {
|
|
114
|
+
type: "array",
|
|
115
|
+
items: { type: "number" },
|
|
116
|
+
description: "UIDs of emails to move.",
|
|
117
|
+
},
|
|
118
|
+
destination: {
|
|
119
|
+
type: "string",
|
|
120
|
+
description: "Destination folder path.",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
required: ["uids", "destination"],
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "mark_email",
|
|
128
|
+
description: 'Set or unset flags on one or more emails. Common flags: "\\Seen" (read), "\\Flagged" (starred).',
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: "object",
|
|
131
|
+
properties: {
|
|
132
|
+
folder: {
|
|
133
|
+
type: "string",
|
|
134
|
+
description: "IMAP folder. Defaults to INBOX.",
|
|
135
|
+
},
|
|
136
|
+
uids: {
|
|
137
|
+
type: "array",
|
|
138
|
+
items: { type: "number" },
|
|
139
|
+
description: "UIDs of emails to modify.",
|
|
140
|
+
},
|
|
141
|
+
flags: {
|
|
142
|
+
type: "array",
|
|
143
|
+
items: { type: "string" },
|
|
144
|
+
description: 'Flags to set/unset (e.g., "\\Seen", "\\Flagged").',
|
|
145
|
+
},
|
|
146
|
+
action: {
|
|
147
|
+
type: "string",
|
|
148
|
+
enum: ["add", "remove"],
|
|
149
|
+
description: 'Whether to add or remove the flags. Defaults to "add".',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
required: ["uids", "flags"],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "delete_email",
|
|
157
|
+
description: "Delete one or more emails. Moves to Trash by default, or permanently deletes if specified.",
|
|
158
|
+
inputSchema: {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
folder: {
|
|
162
|
+
type: "string",
|
|
163
|
+
description: "IMAP folder. Defaults to INBOX.",
|
|
164
|
+
},
|
|
165
|
+
uids: {
|
|
166
|
+
type: "array",
|
|
167
|
+
items: { type: "number" },
|
|
168
|
+
description: "UIDs of emails to delete.",
|
|
169
|
+
},
|
|
170
|
+
permanent: {
|
|
171
|
+
type: "boolean",
|
|
172
|
+
description: "If true, permanently delete instead of moving to Trash. Defaults to false.",
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
required: ["uids"],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: "list_folders",
|
|
180
|
+
description: "List all IMAP folders with their paths and special-use flags (Inbox, Sent, Trash, etc.).",
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: "object",
|
|
183
|
+
properties: {},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "create_folder",
|
|
188
|
+
description: "Create a new IMAP folder.",
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: "object",
|
|
191
|
+
properties: {
|
|
192
|
+
path: {
|
|
193
|
+
type: "string",
|
|
194
|
+
description: "Folder path to create (e.g., 'Projects/Work').",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
required: ["path"],
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: "download_attachment",
|
|
202
|
+
description: "Download a specific attachment from an email. Returns the attachment content as base64.",
|
|
203
|
+
inputSchema: {
|
|
204
|
+
type: "object",
|
|
205
|
+
properties: {
|
|
206
|
+
folder: {
|
|
207
|
+
type: "string",
|
|
208
|
+
description: "IMAP folder. Defaults to INBOX.",
|
|
209
|
+
},
|
|
210
|
+
uid: {
|
|
211
|
+
type: "number",
|
|
212
|
+
description: "UID of the email containing the attachment.",
|
|
213
|
+
},
|
|
214
|
+
partId: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "MIME part ID of the attachment (from get_email attachment metadata).",
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
required: ["uid", "partId"],
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "get_email_raw",
|
|
224
|
+
description: "Export an email as raw .eml (RFC 822 source). Useful for archival or forwarding.",
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: "object",
|
|
227
|
+
properties: {
|
|
228
|
+
folder: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "IMAP folder. Defaults to INBOX.",
|
|
231
|
+
},
|
|
232
|
+
uid: {
|
|
233
|
+
type: "number",
|
|
234
|
+
description: "UID of the email to export.",
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
required: ["uid"],
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
];
|
|
241
|
+
export async function handleEmailTool(name, args, imapService, smtpService) {
|
|
242
|
+
try {
|
|
243
|
+
const folder = args.folder || "INBOX";
|
|
244
|
+
switch (name) {
|
|
245
|
+
case "list_emails": {
|
|
246
|
+
const query = args.query ? parseSearchQuery(args.query) : {};
|
|
247
|
+
const limit = args.limit || 20;
|
|
248
|
+
const offset = args.offset || 0;
|
|
249
|
+
const emails = await imapService.searchEmails(folder, query, {
|
|
250
|
+
limit,
|
|
251
|
+
offset,
|
|
252
|
+
});
|
|
253
|
+
return ok(JSON.stringify(emails, null, 2));
|
|
254
|
+
}
|
|
255
|
+
case "get_email": {
|
|
256
|
+
const uid = args.uid;
|
|
257
|
+
const email = await imapService.fetchEmail(folder, uid);
|
|
258
|
+
return ok(JSON.stringify(email, null, 2));
|
|
259
|
+
}
|
|
260
|
+
case "send_email": {
|
|
261
|
+
const result = await smtpService.sendEmail({
|
|
262
|
+
to: args.to,
|
|
263
|
+
cc: args.cc,
|
|
264
|
+
bcc: args.bcc,
|
|
265
|
+
subject: args.subject,
|
|
266
|
+
text: args.text,
|
|
267
|
+
html: args.html,
|
|
268
|
+
attachments: args.attachments,
|
|
269
|
+
});
|
|
270
|
+
return ok(JSON.stringify({ status: "sent", ...result }));
|
|
271
|
+
}
|
|
272
|
+
case "move_email": {
|
|
273
|
+
const uids = args.uids;
|
|
274
|
+
const destination = args.destination;
|
|
275
|
+
await imapService.moveEmails(folder, uids, destination);
|
|
276
|
+
return ok(JSON.stringify({ status: "moved", uids, destination }));
|
|
277
|
+
}
|
|
278
|
+
case "mark_email": {
|
|
279
|
+
const uids = args.uids;
|
|
280
|
+
const flags = args.flags;
|
|
281
|
+
const action = args.action || "add";
|
|
282
|
+
await imapService.markEmails(folder, uids, flags, action);
|
|
283
|
+
return ok(JSON.stringify({ status: "updated", uids, flags, action }));
|
|
284
|
+
}
|
|
285
|
+
case "delete_email": {
|
|
286
|
+
const uids = args.uids;
|
|
287
|
+
const permanent = args.permanent || false;
|
|
288
|
+
await imapService.deleteEmails(folder, uids, permanent);
|
|
289
|
+
return ok(JSON.stringify({
|
|
290
|
+
status: permanent ? "permanently_deleted" : "moved_to_trash",
|
|
291
|
+
uids,
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
294
|
+
case "list_folders": {
|
|
295
|
+
const folders = await imapService.listFolders();
|
|
296
|
+
return ok(JSON.stringify(folders, null, 2));
|
|
297
|
+
}
|
|
298
|
+
case "create_folder": {
|
|
299
|
+
const path = args.path;
|
|
300
|
+
await imapService.createFolder(path);
|
|
301
|
+
return ok(JSON.stringify({ status: "created", path }));
|
|
302
|
+
}
|
|
303
|
+
case "download_attachment": {
|
|
304
|
+
const uid = args.uid;
|
|
305
|
+
const partId = args.partId;
|
|
306
|
+
const attachment = await imapService.downloadAttachment(folder, uid, partId);
|
|
307
|
+
return ok(JSON.stringify({
|
|
308
|
+
filename: attachment.filename,
|
|
309
|
+
contentType: attachment.contentType,
|
|
310
|
+
size: attachment.size,
|
|
311
|
+
content: attachment.content.toString("base64"),
|
|
312
|
+
}));
|
|
313
|
+
}
|
|
314
|
+
case "get_email_raw": {
|
|
315
|
+
const uid = args.uid;
|
|
316
|
+
const raw = await imapService.fetchRawEmail(folder, uid);
|
|
317
|
+
return ok(raw);
|
|
318
|
+
}
|
|
319
|
+
default:
|
|
320
|
+
return error(`Unknown tool: ${name}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
const pimError = toPimError(err instanceof Error ? err : new Error(String(err)));
|
|
325
|
+
return error(`${pimError.message}${pimError.isRetryable ? " (retryable)" : ""}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function ok(text) {
|
|
329
|
+
return { content: [{ type: "text", text }] };
|
|
330
|
+
}
|
|
331
|
+
function error(text) {
|
|
332
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=emailTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailTools.js","sourceRoot":"","sources":["../../src/tools/emailTools.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miguelarios/email-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for email via IMAP/SMTP — read, search, send, and manage emails",
|
|
5
|
+
"keywords": ["mcp", "email", "imap", "smtp", "mailbox"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Miguel Rios",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/miguelarios/pim-agents.git",
|
|
11
|
+
"directory": "packages/email-mcp"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/miguelarios/pim-agents",
|
|
14
|
+
"bugs": "https://github.com/miguelarios/pim-agents/issues",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"email-mcp": "dist/bin/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"lint": "biome check .",
|
|
24
|
+
"start": "node dist/bin/cli.js"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@miguelarios/pim-core": "^0.1.0",
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
29
|
+
"imapflow": "^1.0.0",
|
|
30
|
+
"mailparser": "^3.7.0",
|
|
31
|
+
"nodemailer": "^6.9.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/nodemailer": "^6.4.0",
|
|
35
|
+
"@types/node": "^20.0.0",
|
|
36
|
+
"typescript": "^5.7.0",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|