@honest-magic/mail-mcp 1.0.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.
@@ -0,0 +1,200 @@
1
+ import { ImapClient } from '../protocol/imap.js';
2
+ import { SmtpClient } from '../protocol/smtp.js';
3
+ import { htmlToMarkdown } from '../utils/markdown.js';
4
+ export class MailService {
5
+ readOnly;
6
+ imapClient;
7
+ smtpClient;
8
+ account;
9
+ smtpConnected = false;
10
+ constructor(account, readOnly = false) {
11
+ this.readOnly = readOnly;
12
+ this.account = account;
13
+ this.imapClient = new ImapClient(account);
14
+ this.smtpClient = new SmtpClient(account);
15
+ }
16
+ async connect() {
17
+ await this.imapClient.connect();
18
+ }
19
+ async ensureSmtp() {
20
+ if (!this.smtpConnected) {
21
+ await this.smtpClient.connect();
22
+ this.smtpConnected = true;
23
+ }
24
+ }
25
+ async disconnect() {
26
+ await this.imapClient.disconnect();
27
+ // nodemailer transporter doesn't strictly need closing, but good practice if pooling
28
+ }
29
+ async listEmails(folder = 'INBOX', count = 10) {
30
+ return this.imapClient.listMessages(folder, count);
31
+ }
32
+ async searchEmails(query, folder = 'INBOX', count = 10) {
33
+ const criteria = {};
34
+ if (query.from)
35
+ criteria.from = query.from;
36
+ if (query.subject)
37
+ criteria.subject = query.subject;
38
+ if (query.since)
39
+ criteria.since = query.since;
40
+ if (query.before)
41
+ criteria.before = query.before;
42
+ if (query.keywords)
43
+ criteria.body = query.keywords;
44
+ return this.imapClient.searchMessages(criteria, folder, count);
45
+ }
46
+ async sendEmail(to, subject, body, isHtml = false, cc, bcc) {
47
+ // Build raw message before sending so we can append to Sent folder
48
+ const rawMessage = [
49
+ `From: ${this.account.user}`,
50
+ `To: ${to}`,
51
+ ...(cc ? [`Cc: ${cc}`] : []),
52
+ ...(bcc ? [`Bcc: ${bcc}`] : []),
53
+ `Subject: ${subject}`,
54
+ 'MIME-Version: 1.0',
55
+ `Content-Type: ${isHtml ? 'text/html' : 'text/plain'}; charset=utf-8`,
56
+ '',
57
+ body
58
+ ].join('\r\n');
59
+ await this.ensureSmtp();
60
+ const info = await this.smtpClient.send(to, subject, body, isHtml, cc, bcc);
61
+ try {
62
+ await this.imapClient.appendMessage('Sent', rawMessage, ['\\Seen']);
63
+ }
64
+ catch (e) {
65
+ console.error('Failed to append to Sent folder:', e);
66
+ }
67
+ return info;
68
+ }
69
+ async createDraft(to, subject, body, isHtml = false, cc, bcc) {
70
+ const headers = [
71
+ `From: ${this.account.user}`,
72
+ `To: ${to}`,
73
+ ...(cc ? [`Cc: ${cc}`] : []),
74
+ ...(bcc ? [`Bcc: ${bcc}`] : []),
75
+ `Subject: ${subject}`,
76
+ 'MIME-Version: 1.0',
77
+ `Content-Type: ${isHtml ? 'text/html' : 'text/plain'}; charset=utf-8`,
78
+ '',
79
+ body
80
+ ].join('\r\n');
81
+ await this.imapClient.appendMessage('Drafts', headers, ['\\Draft']);
82
+ }
83
+ async readEmail(uid, folder = 'INBOX') {
84
+ const parsed = await this.imapClient.fetchMessageBody(uid, folder);
85
+ let content = '';
86
+ if (parsed.html) {
87
+ let html = parsed.html;
88
+ // Convert inline images to base64 if needed
89
+ if (parsed.attachments) {
90
+ for (const att of parsed.attachments) {
91
+ if (att.contentId && att.content && att.contentType.startsWith('image/')) {
92
+ const base64 = att.content.toString('base64');
93
+ const dataUri = `data:${att.contentType};base64,${base64}`;
94
+ const cidRegex = new RegExp(`cid:${att.contentId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'g');
95
+ html = html.replace(cidRegex, dataUri);
96
+ }
97
+ }
98
+ }
99
+ content = htmlToMarkdown(html);
100
+ }
101
+ else if (parsed.textAsHtml) {
102
+ content = htmlToMarkdown(parsed.textAsHtml);
103
+ }
104
+ else if (parsed.text) {
105
+ content = parsed.text;
106
+ }
107
+ let attachmentInfo = '';
108
+ if (parsed.attachments && parsed.attachments.length > 0) {
109
+ attachmentInfo = '\n\n**Attachments:**\n';
110
+ parsed.attachments.forEach(att => {
111
+ attachmentInfo += `- ${att.filename || 'Unnamed'} (${att.contentType}, ${Math.round(att.size / 1024)} KB)\n`;
112
+ });
113
+ }
114
+ let header = `**From:** ${parsed.from?.text || 'Unknown'}\n`;
115
+ const toText = Array.isArray(parsed.to) ? parsed.to.map(t => t.text).join(', ') : parsed.to?.text;
116
+ header += `**To:** ${toText || 'Unknown'}\n`;
117
+ if (parsed.cc) {
118
+ const ccText = Array.isArray(parsed.cc) ? parsed.cc.map(t => t.text).join(', ') : parsed.cc.text;
119
+ header += `**Cc:** ${ccText}\n`;
120
+ }
121
+ header += `**Subject:** ${parsed.subject || 'No Subject'}\n`;
122
+ header += `**Date:** ${parsed.date?.toISOString() || 'Unknown'}\n`;
123
+ // Check for thread ID in headers
124
+ const threadId = parsed.headers.get('x-gm-thrid');
125
+ if (threadId) {
126
+ header += `**Thread ID:** ${threadId}\n`;
127
+ }
128
+ // Expose Message-ID so non-Gmail callers have a threadId for get_thread
129
+ const messageId = parsed.messageId || parsed.headers.get('message-id');
130
+ if (messageId) {
131
+ header += `**Message-ID:** ${messageId}\n`;
132
+ }
133
+ header += `\n---\n\n`;
134
+ return header + content + attachmentInfo;
135
+ }
136
+ async getThread(threadId, folder = 'INBOX') {
137
+ return this.imapClient.fetchThreadMessages(threadId, folder);
138
+ }
139
+ async downloadAttachment(uid, filename, folder = 'INBOX') {
140
+ const parsed = await this.imapClient.fetchMessageBody(uid, folder);
141
+ if (!parsed.attachments || parsed.attachments.length === 0) {
142
+ throw new Error('No attachments found in this email');
143
+ }
144
+ const attachment = parsed.attachments.find(a => a.filename === filename);
145
+ if (!attachment) {
146
+ throw new Error(`Attachment "${filename}" not found`);
147
+ }
148
+ return {
149
+ content: attachment.content,
150
+ contentType: attachment.contentType
151
+ };
152
+ }
153
+ async extractAttachmentText(uid, filename, folder = 'INBOX') {
154
+ const { content, contentType } = await this.downloadAttachment(uid, filename, folder);
155
+ if (contentType === 'application/pdf') {
156
+ const pdf = await import('pdf-parse');
157
+ // Some modules have a .default property when imported via dynamic import in ESM
158
+ const pdfParser = pdf.default || pdf;
159
+ const data = await pdfParser(content);
160
+ return data.text;
161
+ }
162
+ else if (contentType.startsWith('text/')) {
163
+ return content.toString('utf-8');
164
+ }
165
+ else {
166
+ throw new Error(`Extraction not supported for content type: ${contentType}`);
167
+ }
168
+ }
169
+ async listFolders() {
170
+ return this.imapClient.listFolders();
171
+ }
172
+ async moveMessage(uid, sourceFolder, targetFolder) {
173
+ return this.imapClient.moveMessage(uid, sourceFolder, targetFolder);
174
+ }
175
+ async modifyLabels(uid, folder, addLabels, removeLabels) {
176
+ return this.imapClient.modifyLabels(uid, folder, addLabels, removeLabels);
177
+ }
178
+ async batchOperations(uids, folder, operation) {
179
+ if (uids.length === 0) {
180
+ throw new Error('No UIDs provided for batch operation');
181
+ }
182
+ if (uids.length > 100) {
183
+ throw new Error('Batch operations are limited to 100 emails at once');
184
+ }
185
+ if (operation.type === 'move') {
186
+ await this.imapClient.batchMoveMessages(uids, folder, operation.targetFolder);
187
+ }
188
+ else if (operation.type === 'delete') {
189
+ await this.imapClient.batchDeleteMessages(uids, folder);
190
+ }
191
+ else if (operation.type === 'label') {
192
+ await this.imapClient.batchModifyLabels(uids, folder, operation.addLabels || [], operation.removeLabels || []);
193
+ }
194
+ else {
195
+ throw new Error(`Unknown batch operation type: ${operation.type}`);
196
+ }
197
+ return { processed: uids.length };
198
+ }
199
+ }
200
+ //# sourceMappingURL=mail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/services/mail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export type AuthType = 'login' | 'oauth2';
2
+ export interface EmailAccount {
3
+ id: string;
4
+ name: string;
5
+ host: string;
6
+ port: number;
7
+ smtpHost?: string;
8
+ smtpPort?: number;
9
+ user: string;
10
+ authType: AuthType;
11
+ useTLS: boolean;
12
+ }
13
+ export interface Credentials {
14
+ password?: string;
15
+ accessToken?: string;
16
+ refreshToken?: string;
17
+ expiryDate?: number;
18
+ }
@@ -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":""}
@@ -0,0 +1 @@
1
+ export declare function htmlToMarkdown(html: string): string;
@@ -0,0 +1,11 @@
1
+ import TurndownService from 'turndown';
2
+ const turndownService = new TurndownService({
3
+ headingStyle: 'atx',
4
+ codeBlockStyle: 'fenced',
5
+ });
6
+ export function htmlToMarkdown(html) {
7
+ if (!html)
8
+ return '';
9
+ return turndownService.turndown(html);
10
+ }
11
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,UAAU,CAAC;AAEvC,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC;IAC1C,YAAY,EAAE,KAAK;IACnB,cAAc,EAAE,QAAQ;CACzB,CAAC,CAAC;AAEH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@honest-magic/mail-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for AI-powered email access via IMAP and SMTP",
5
+ "keywords": ["mcp", "email", "imap", "smtp", "ai", "llm", "model-context-protocol"],
6
+ "author": "honest-magic",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/honest-magic/mail-mcp#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/honest-magic/mail-mcp.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/honest-magic/mail-mcp/issues"
15
+ },
16
+ "engines": {
17
+ "node": ">=18.0.0"
18
+ },
19
+ "type": "module",
20
+ "bin": {
21
+ "mail-mcp": "dist/index.js"
22
+ },
23
+ "files": ["dist", "README.md", "LICENSE"],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "start": "node dist/index.js",
30
+ "test": "vitest run"
31
+ },
32
+ "dependencies": {
33
+ "@modelcontextprotocol/sdk": "^1.27.1",
34
+ "cross-keychain": "^1.1.0",
35
+ "dotenv": "^17.3.1",
36
+ "imapflow": "^1.2.16",
37
+ "mailparser": "^3.9.4",
38
+ "nodemailer": "^8.0.3",
39
+ "pdf-parse": "^2.4.5",
40
+ "turndown": "^7.2.2",
41
+ "zod": "^4.3.6"
42
+ },
43
+ "devDependencies": {
44
+ "@types/mailparser": "^3.4.6",
45
+ "@types/node": "^25.5.0",
46
+ "@types/nodemailer": "^7.0.11",
47
+ "@types/pdf-parse": "^1.1.5",
48
+ "@types/turndown": "^5.0.6",
49
+ "ts-node": "^10.9.2",
50
+ "typescript": "^5.9.3",
51
+ "vitest": "^4.1.0"
52
+ }
53
+ }