better-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 +123 -0
- package/dist/backends/imap.d.ts +46 -0
- package/dist/backends/imap.d.ts.map +1 -0
- package/dist/backends/imap.js +300 -0
- package/dist/backends/imap.js.map +1 -0
- package/dist/backends/jmap.d.ts +33 -0
- package/dist/backends/jmap.d.ts.map +1 -0
- package/dist/backends/jmap.js +374 -0
- package/dist/backends/jmap.js.map +1 -0
- package/dist/imap/client.d.ts +36 -0
- package/dist/imap/client.d.ts.map +1 -0
- package/dist/imap/client.js +212 -0
- package/dist/imap/client.js.map +1 -0
- package/dist/imap/parser.d.ts +73 -0
- package/dist/imap/parser.d.ts.map +1 -0
- package/dist/imap/parser.js +349 -0
- package/dist/imap/parser.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/smtp/client.d.ts +39 -0
- package/dist/smtp/client.d.ts.map +1 -0
- package/dist/smtp/client.js +241 -0
- package/dist/smtp/client.js.map +1 -0
- package/dist/tools/register.d.ts +4 -0
- package/dist/tools/register.d.ts.map +1 -0
- package/dist/tools/register.js +147 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IMAP response parser.
|
|
3
|
+
*
|
|
4
|
+
* Handles tagged/untagged responses, parenthesized lists (flags, envelopes,
|
|
5
|
+
* body structures), and RFC 2047 encoded-word decoding.
|
|
6
|
+
*/
|
|
7
|
+
export interface ImapResponse {
|
|
8
|
+
tag: string;
|
|
9
|
+
type?: string;
|
|
10
|
+
num?: number;
|
|
11
|
+
text: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ImapAddress {
|
|
14
|
+
name: string;
|
|
15
|
+
email: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ParsedEnvelope {
|
|
18
|
+
date: string;
|
|
19
|
+
subject: string;
|
|
20
|
+
from: ImapAddress[];
|
|
21
|
+
sender: ImapAddress[];
|
|
22
|
+
replyTo: ImapAddress[];
|
|
23
|
+
to: ImapAddress[];
|
|
24
|
+
cc: ImapAddress[];
|
|
25
|
+
bcc: ImapAddress[];
|
|
26
|
+
inReplyTo: string;
|
|
27
|
+
messageId: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ParsedFetch {
|
|
30
|
+
uid?: number;
|
|
31
|
+
flags?: string[];
|
|
32
|
+
envelope?: ParsedEnvelope;
|
|
33
|
+
bodyText?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function parseResponseLine(line: string): ImapResponse;
|
|
36
|
+
/**
|
|
37
|
+
* Parses an IMAP parenthesized list into a nested array.
|
|
38
|
+
* Handles NIL, quoted strings, literals (as pre-substituted text), and atoms.
|
|
39
|
+
*
|
|
40
|
+
* Example: `(\\Seen \\Flagged)` → ["\\Seen", "\\Flagged"]
|
|
41
|
+
* Example: `("hello" NIL)` → ["hello", null]
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseParenList(data: string, startIndex?: number): {
|
|
44
|
+
value: any[];
|
|
45
|
+
endIndex: number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Parses the data items from a FETCH response.
|
|
49
|
+
* Input: the text after "* N FETCH", e.g. "(UID 42 FLAGS (\\Seen) ENVELOPE (...))"
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseFetchResponse(text: string): ParsedFetch;
|
|
52
|
+
/**
|
|
53
|
+
* Parses UIDs from a SEARCH response text.
|
|
54
|
+
* Input: "1 4 9 23" → [1, 4, 9, 23]
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseSearchResponse(text: string): number[];
|
|
57
|
+
/**
|
|
58
|
+
* Parses a LIST response line.
|
|
59
|
+
* Format: (flags) "delimiter" "mailbox-name"
|
|
60
|
+
* Input text (after "* LIST"): `(\HasNoChildren) "/" "INBOX"`
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseListResponse(text: string): {
|
|
63
|
+
flags: string[];
|
|
64
|
+
delimiter: string;
|
|
65
|
+
name: string;
|
|
66
|
+
} | null;
|
|
67
|
+
/**
|
|
68
|
+
* Decodes RFC 2047 encoded words in a string.
|
|
69
|
+
* Format: =?charset?encoding?encoded-text?=
|
|
70
|
+
* Supports B (base64) and Q (quoted-printable) encodings.
|
|
71
|
+
*/
|
|
72
|
+
export declare function decodeRfc2047(input: string): string;
|
|
73
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/imap/parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,EAAE,EAAE,WAAW,EAAE,CAAC;IAClB,EAAE,EAAE,WAAW,EAAE,CAAC;IAClB,GAAG,EAAE,WAAW,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA6B5D;AA6BD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAAI,GAAG;IAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA2C/F;AAmCD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA2E5D;AA2CD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAO1D;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAmC3G;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAyBnD"}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IMAP response parser.
|
|
4
|
+
*
|
|
5
|
+
* Handles tagged/untagged responses, parenthesized lists (flags, envelopes,
|
|
6
|
+
* body structures), and RFC 2047 encoded-word decoding.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.parseResponseLine = parseResponseLine;
|
|
10
|
+
exports.parseParenList = parseParenList;
|
|
11
|
+
exports.parseFetchResponse = parseFetchResponse;
|
|
12
|
+
exports.parseSearchResponse = parseSearchResponse;
|
|
13
|
+
exports.parseListResponse = parseListResponse;
|
|
14
|
+
exports.decodeRfc2047 = decodeRfc2047;
|
|
15
|
+
// --- Response line parsing ---
|
|
16
|
+
function parseResponseLine(line) {
|
|
17
|
+
// Continuation response
|
|
18
|
+
if (line.startsWith("+ ") || line === "+") {
|
|
19
|
+
return { tag: "+", text: line.substring(2) };
|
|
20
|
+
}
|
|
21
|
+
// Untagged response: * ...
|
|
22
|
+
if (line.startsWith("* ")) {
|
|
23
|
+
return parseUntagged(line.substring(2));
|
|
24
|
+
}
|
|
25
|
+
// Tagged response: A1 OK/NO/BAD ...
|
|
26
|
+
const spaceIdx = line.indexOf(" ");
|
|
27
|
+
if (spaceIdx === -1) {
|
|
28
|
+
return { tag: line, text: "" };
|
|
29
|
+
}
|
|
30
|
+
const tag = line.substring(0, spaceIdx);
|
|
31
|
+
const rest = line.substring(spaceIdx + 1);
|
|
32
|
+
const typeMatch = rest.match(/^(OK|NO|BAD)\b\s*(.*)/i);
|
|
33
|
+
if (typeMatch) {
|
|
34
|
+
return {
|
|
35
|
+
tag,
|
|
36
|
+
type: typeMatch[1].toUpperCase(),
|
|
37
|
+
text: typeMatch[2],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return { tag, text: rest };
|
|
41
|
+
}
|
|
42
|
+
function parseUntagged(rest) {
|
|
43
|
+
// Check for numeric prefix: "* 5 EXISTS", "* 42 FETCH (...)"
|
|
44
|
+
const numMatch = rest.match(/^(\d+)\s+(\S+)\s*(.*)/);
|
|
45
|
+
if (numMatch) {
|
|
46
|
+
return {
|
|
47
|
+
tag: "*",
|
|
48
|
+
num: parseInt(numMatch[1], 10),
|
|
49
|
+
type: numMatch[2].toUpperCase(),
|
|
50
|
+
text: numMatch[3],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Non-numeric: "* OK ...", "* SEARCH 1 4 9", "* LIST ..."
|
|
54
|
+
const typeMatch = rest.match(/^(\S+)\s*(.*)/);
|
|
55
|
+
if (typeMatch) {
|
|
56
|
+
return {
|
|
57
|
+
tag: "*",
|
|
58
|
+
type: typeMatch[1].toUpperCase(),
|
|
59
|
+
text: typeMatch[2],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return { tag: "*", text: rest };
|
|
63
|
+
}
|
|
64
|
+
// --- Parenthesized list parser ---
|
|
65
|
+
/**
|
|
66
|
+
* Parses an IMAP parenthesized list into a nested array.
|
|
67
|
+
* Handles NIL, quoted strings, literals (as pre-substituted text), and atoms.
|
|
68
|
+
*
|
|
69
|
+
* Example: `(\\Seen \\Flagged)` → ["\\Seen", "\\Flagged"]
|
|
70
|
+
* Example: `("hello" NIL)` → ["hello", null]
|
|
71
|
+
*/
|
|
72
|
+
function parseParenList(data, startIndex = 0) {
|
|
73
|
+
const result = [];
|
|
74
|
+
let i = startIndex;
|
|
75
|
+
// Skip leading whitespace
|
|
76
|
+
while (i < data.length && data[i] === " ")
|
|
77
|
+
i++;
|
|
78
|
+
if (data[i] !== "(") {
|
|
79
|
+
throw new Error(`Expected '(' at position ${i}, got '${data[i]}'`);
|
|
80
|
+
}
|
|
81
|
+
i++; // skip opening paren
|
|
82
|
+
while (i < data.length) {
|
|
83
|
+
// Skip whitespace
|
|
84
|
+
while (i < data.length && data[i] === " ")
|
|
85
|
+
i++;
|
|
86
|
+
if (i >= data.length)
|
|
87
|
+
break;
|
|
88
|
+
const ch = data[i];
|
|
89
|
+
if (ch === ")") {
|
|
90
|
+
return { value: result, endIndex: i + 1 };
|
|
91
|
+
}
|
|
92
|
+
if (ch === "(") {
|
|
93
|
+
// Nested list
|
|
94
|
+
const nested = parseParenList(data, i);
|
|
95
|
+
result.push(nested.value);
|
|
96
|
+
i = nested.endIndex;
|
|
97
|
+
}
|
|
98
|
+
else if (ch === '"') {
|
|
99
|
+
// Quoted string
|
|
100
|
+
const { value, endIndex } = parseQuotedString(data, i);
|
|
101
|
+
result.push(value);
|
|
102
|
+
i = endIndex;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Atom or NIL
|
|
106
|
+
const { value, endIndex } = parseAtom(data, i);
|
|
107
|
+
result.push(value === "NIL" ? null : value);
|
|
108
|
+
i = endIndex;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { value: result, endIndex: i };
|
|
112
|
+
}
|
|
113
|
+
function parseQuotedString(data, startIndex) {
|
|
114
|
+
let i = startIndex + 1; // skip opening quote
|
|
115
|
+
let result = "";
|
|
116
|
+
while (i < data.length) {
|
|
117
|
+
if (data[i] === "\\") {
|
|
118
|
+
// Escaped character
|
|
119
|
+
i++;
|
|
120
|
+
if (i < data.length) {
|
|
121
|
+
result += data[i];
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else if (data[i] === '"') {
|
|
126
|
+
return { value: result, endIndex: i + 1 };
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
result += data[i];
|
|
130
|
+
i++;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { value: result, endIndex: i };
|
|
134
|
+
}
|
|
135
|
+
function parseAtom(data, startIndex) {
|
|
136
|
+
let i = startIndex;
|
|
137
|
+
while (i < data.length && data[i] !== " " && data[i] !== ")" && data[i] !== "(") {
|
|
138
|
+
i++;
|
|
139
|
+
}
|
|
140
|
+
return { value: data.substring(startIndex, i), endIndex: i };
|
|
141
|
+
}
|
|
142
|
+
// --- FETCH response parsing ---
|
|
143
|
+
/**
|
|
144
|
+
* Parses the data items from a FETCH response.
|
|
145
|
+
* Input: the text after "* N FETCH", e.g. "(UID 42 FLAGS (\\Seen) ENVELOPE (...))"
|
|
146
|
+
*/
|
|
147
|
+
function parseFetchResponse(text) {
|
|
148
|
+
const result = {};
|
|
149
|
+
// Strip outer parens
|
|
150
|
+
const trimmed = text.trim();
|
|
151
|
+
if (!trimmed.startsWith("(") || !trimmed.endsWith(")")) {
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
const inner = trimmed.substring(1, trimmed.length - 1);
|
|
155
|
+
let i = 0;
|
|
156
|
+
while (i < inner.length) {
|
|
157
|
+
// Skip whitespace
|
|
158
|
+
while (i < inner.length && inner[i] === " ")
|
|
159
|
+
i++;
|
|
160
|
+
if (i >= inner.length)
|
|
161
|
+
break;
|
|
162
|
+
// Read keyword
|
|
163
|
+
const kwStart = i;
|
|
164
|
+
while (i < inner.length && inner[i] !== " " && inner[i] !== "(")
|
|
165
|
+
i++;
|
|
166
|
+
const keyword = inner.substring(kwStart, i).toUpperCase();
|
|
167
|
+
// Skip whitespace
|
|
168
|
+
while (i < inner.length && inner[i] === " ")
|
|
169
|
+
i++;
|
|
170
|
+
if (keyword === "UID") {
|
|
171
|
+
const { value, endIndex } = parseAtom(inner, i);
|
|
172
|
+
result.uid = parseInt(value, 10);
|
|
173
|
+
i = endIndex;
|
|
174
|
+
}
|
|
175
|
+
else if (keyword === "FLAGS") {
|
|
176
|
+
const { value, endIndex } = parseParenList(inner, i);
|
|
177
|
+
result.flags = value;
|
|
178
|
+
i = endIndex;
|
|
179
|
+
}
|
|
180
|
+
else if (keyword === "ENVELOPE") {
|
|
181
|
+
const { value, endIndex } = parseParenList(inner, i);
|
|
182
|
+
result.envelope = mapEnvelopeList(value);
|
|
183
|
+
i = endIndex;
|
|
184
|
+
}
|
|
185
|
+
else if (keyword.startsWith("BODY[")) {
|
|
186
|
+
// Body text: BODY[TEXT] or BODY[1] etc.
|
|
187
|
+
// Value follows as a literal or quoted string
|
|
188
|
+
if (inner[i] === '"') {
|
|
189
|
+
const { value, endIndex } = parseQuotedString(inner, i);
|
|
190
|
+
result.bodyText = value;
|
|
191
|
+
i = endIndex;
|
|
192
|
+
}
|
|
193
|
+
else if (inner[i] === "{") {
|
|
194
|
+
// Literal: {N}\r\n<data> — in our usage, literals are pre-joined by the client
|
|
195
|
+
// so this appears as {N} followed by the data after client processing
|
|
196
|
+
const braceEnd = inner.indexOf("}", i);
|
|
197
|
+
if (braceEnd !== -1) {
|
|
198
|
+
const size = parseInt(inner.substring(i + 1, braceEnd), 10);
|
|
199
|
+
// Data follows after the closing brace (client pre-processes \r\n)
|
|
200
|
+
const dataStart = braceEnd + 1;
|
|
201
|
+
result.bodyText = inner.substring(dataStart, dataStart + size);
|
|
202
|
+
i = dataStart + size;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const { value, endIndex } = parseAtom(inner, i);
|
|
207
|
+
result.bodyText = value === "NIL" ? undefined : value;
|
|
208
|
+
i = endIndex;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// Skip unknown data item value
|
|
213
|
+
if (i < inner.length && inner[i] === "(") {
|
|
214
|
+
const { endIndex } = parseParenList(inner, i);
|
|
215
|
+
i = endIndex;
|
|
216
|
+
}
|
|
217
|
+
else if (i < inner.length && inner[i] === '"') {
|
|
218
|
+
const { endIndex } = parseQuotedString(inner, i);
|
|
219
|
+
i = endIndex;
|
|
220
|
+
}
|
|
221
|
+
else if (i < inner.length) {
|
|
222
|
+
const { endIndex } = parseAtom(inner, i);
|
|
223
|
+
i = endIndex;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
// --- Envelope parsing ---
|
|
230
|
+
/**
|
|
231
|
+
* Maps a parsed parenthesized list (from ENVELOPE) to a ParsedEnvelope.
|
|
232
|
+
* RFC 3501 §7.4.2: (date subject from sender reply-to to cc bcc in-reply-to message-id)
|
|
233
|
+
*/
|
|
234
|
+
function mapEnvelopeList(list) {
|
|
235
|
+
return {
|
|
236
|
+
date: typeof list[0] === "string" ? list[0] : "",
|
|
237
|
+
subject: typeof list[1] === "string" ? decodeRfc2047(list[1]) : "",
|
|
238
|
+
from: parseAddressList(list[2]),
|
|
239
|
+
sender: parseAddressList(list[3]),
|
|
240
|
+
replyTo: parseAddressList(list[4]),
|
|
241
|
+
to: parseAddressList(list[5]),
|
|
242
|
+
cc: parseAddressList(list[6]),
|
|
243
|
+
bcc: parseAddressList(list[7]),
|
|
244
|
+
inReplyTo: typeof list[8] === "string" ? list[8] : "",
|
|
245
|
+
messageId: typeof list[9] === "string" ? list[9] : "",
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Parses IMAP address list: ((name adl mailbox host) ...)
|
|
250
|
+
* Each address is (personal-name at-domain-list mailbox host)
|
|
251
|
+
* Email = mailbox@host, display name = personal-name
|
|
252
|
+
*/
|
|
253
|
+
function parseAddressList(data) {
|
|
254
|
+
if (!Array.isArray(data))
|
|
255
|
+
return [];
|
|
256
|
+
return data
|
|
257
|
+
.filter((addr) => Array.isArray(addr))
|
|
258
|
+
.map((addr) => {
|
|
259
|
+
const name = typeof addr[0] === "string" ? decodeRfc2047(addr[0]) : "";
|
|
260
|
+
const mailbox = typeof addr[2] === "string" ? addr[2] : "";
|
|
261
|
+
const host = typeof addr[3] === "string" ? addr[3] : "";
|
|
262
|
+
const email = host ? `${mailbox}@${host}` : mailbox;
|
|
263
|
+
return { name, email };
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// --- SEARCH response parsing ---
|
|
267
|
+
/**
|
|
268
|
+
* Parses UIDs from a SEARCH response text.
|
|
269
|
+
* Input: "1 4 9 23" → [1, 4, 9, 23]
|
|
270
|
+
*/
|
|
271
|
+
function parseSearchResponse(text) {
|
|
272
|
+
if (!text.trim())
|
|
273
|
+
return [];
|
|
274
|
+
return text
|
|
275
|
+
.trim()
|
|
276
|
+
.split(/\s+/)
|
|
277
|
+
.map((s) => parseInt(s, 10))
|
|
278
|
+
.filter((n) => !isNaN(n));
|
|
279
|
+
}
|
|
280
|
+
// --- LIST response parsing ---
|
|
281
|
+
/**
|
|
282
|
+
* Parses a LIST response line.
|
|
283
|
+
* Format: (flags) "delimiter" "mailbox-name"
|
|
284
|
+
* Input text (after "* LIST"): `(\HasNoChildren) "/" "INBOX"`
|
|
285
|
+
*/
|
|
286
|
+
function parseListResponse(text) {
|
|
287
|
+
const trimmed = text.trim();
|
|
288
|
+
if (!trimmed.startsWith("("))
|
|
289
|
+
return null;
|
|
290
|
+
// Parse flags
|
|
291
|
+
const { value: flags, endIndex } = parseParenList(trimmed, 0);
|
|
292
|
+
let i = endIndex;
|
|
293
|
+
while (i < trimmed.length && trimmed[i] === " ")
|
|
294
|
+
i++;
|
|
295
|
+
// Parse delimiter (quoted string or NIL)
|
|
296
|
+
let delimiter = "/";
|
|
297
|
+
if (trimmed[i] === '"') {
|
|
298
|
+
const { value, endIndex: dEnd } = parseQuotedString(trimmed, i);
|
|
299
|
+
delimiter = value;
|
|
300
|
+
i = dEnd;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
const { value, endIndex: dEnd } = parseAtom(trimmed, i);
|
|
304
|
+
delimiter = value === "NIL" ? "" : value;
|
|
305
|
+
i = dEnd;
|
|
306
|
+
}
|
|
307
|
+
while (i < trimmed.length && trimmed[i] === " ")
|
|
308
|
+
i++;
|
|
309
|
+
// Parse mailbox name (quoted string or atom)
|
|
310
|
+
let name = "";
|
|
311
|
+
if (trimmed[i] === '"') {
|
|
312
|
+
const { value } = parseQuotedString(trimmed, i);
|
|
313
|
+
name = value;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
const { value } = parseAtom(trimmed, i);
|
|
317
|
+
name = value;
|
|
318
|
+
}
|
|
319
|
+
return { flags: flags, delimiter, name };
|
|
320
|
+
}
|
|
321
|
+
// --- RFC 2047 encoded-word decoding ---
|
|
322
|
+
/**
|
|
323
|
+
* Decodes RFC 2047 encoded words in a string.
|
|
324
|
+
* Format: =?charset?encoding?encoded-text?=
|
|
325
|
+
* Supports B (base64) and Q (quoted-printable) encodings.
|
|
326
|
+
*/
|
|
327
|
+
function decodeRfc2047(input) {
|
|
328
|
+
if (!input || !input.includes("=?"))
|
|
329
|
+
return input;
|
|
330
|
+
return input.replace(/=\?([^?]+)\?([BbQq])\?([^?]*)\?=/g, (_match, _charset, encoding, encoded) => {
|
|
331
|
+
try {
|
|
332
|
+
if (encoding.toUpperCase() === "B") {
|
|
333
|
+
return Buffer.from(encoded, "base64").toString("utf-8");
|
|
334
|
+
}
|
|
335
|
+
if (encoding.toUpperCase() === "Q") {
|
|
336
|
+
// Quoted-printable: _ = space, =XX = hex byte
|
|
337
|
+
const decoded = encoded
|
|
338
|
+
.replace(/_/g, " ")
|
|
339
|
+
.replace(/=([0-9A-Fa-f]{2})/g, (_m, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
340
|
+
return Buffer.from(decoded, "binary").toString("utf-8");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Fall through to return original
|
|
345
|
+
}
|
|
346
|
+
return encoded;
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/imap/parser.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const jmap_js_1 = require("./backends/jmap.js");
|
|
7
|
+
const imap_js_1 = require("./backends/imap.js");
|
|
8
|
+
const register_js_1 = require("./tools/register.js");
|
|
9
|
+
function createBackend() {
|
|
10
|
+
const backendType = process.env.EMAIL_BACKEND ?? "jmap";
|
|
11
|
+
if (backendType === "jmap") {
|
|
12
|
+
const token = process.env.JMAP_TOKEN;
|
|
13
|
+
if (!token) {
|
|
14
|
+
throw new Error("JMAP_TOKEN environment variable is required");
|
|
15
|
+
}
|
|
16
|
+
return new jmap_js_1.JmapBackend({
|
|
17
|
+
token,
|
|
18
|
+
sessionUrl: process.env.JMAP_SESSION_URL,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (backendType === "imap") {
|
|
22
|
+
const host = process.env.IMAP_HOST;
|
|
23
|
+
const user = process.env.IMAP_USER;
|
|
24
|
+
const password = process.env.IMAP_PASSWORD;
|
|
25
|
+
if (!host || !user || !password) {
|
|
26
|
+
throw new Error("IMAP_HOST, IMAP_USER, and IMAP_PASSWORD environment variables are required");
|
|
27
|
+
}
|
|
28
|
+
let smtpConfig;
|
|
29
|
+
const smtpHost = process.env.SMTP_HOST;
|
|
30
|
+
if (smtpHost) {
|
|
31
|
+
const smtpUser = process.env.SMTP_USER;
|
|
32
|
+
const smtpPassword = process.env.SMTP_PASSWORD;
|
|
33
|
+
if (!smtpUser || !smtpPassword) {
|
|
34
|
+
throw new Error("SMTP_USER and SMTP_PASSWORD are required when SMTP_HOST is set");
|
|
35
|
+
}
|
|
36
|
+
smtpConfig = {
|
|
37
|
+
host: smtpHost,
|
|
38
|
+
port: parseInt(process.env.SMTP_PORT ?? "587", 10),
|
|
39
|
+
user: smtpUser,
|
|
40
|
+
password: smtpPassword,
|
|
41
|
+
tls: process.env.SMTP_TLS !== "false",
|
|
42
|
+
from: process.env.SMTP_FROM,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return new imap_js_1.ImapBackend({
|
|
46
|
+
host,
|
|
47
|
+
port: parseInt(process.env.IMAP_PORT ?? "993", 10),
|
|
48
|
+
user,
|
|
49
|
+
password,
|
|
50
|
+
tls: process.env.IMAP_TLS !== "false",
|
|
51
|
+
}, smtpConfig);
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Unknown backend: ${backendType}`);
|
|
54
|
+
}
|
|
55
|
+
const server = new mcp_js_1.McpServer({
|
|
56
|
+
name: "better-email-mcp",
|
|
57
|
+
version: "0.1.0",
|
|
58
|
+
});
|
|
59
|
+
const backend = createBackend();
|
|
60
|
+
(0, register_js_1.registerEmailTools)(server, backend);
|
|
61
|
+
async function main() {
|
|
62
|
+
await backend.connect();
|
|
63
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
64
|
+
await server.connect(transport);
|
|
65
|
+
}
|
|
66
|
+
main().catch((err) => {
|
|
67
|
+
console.error("Fatal error:", err);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
70
|
+
//# 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,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal SMTP client using Node's built-in net/tls modules.
|
|
3
|
+
* Supports EHLO, AUTH PLAIN, STARTTLS, and message submission.
|
|
4
|
+
*/
|
|
5
|
+
export interface SmtpClientConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
tls: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class SmtpError extends Error {
|
|
11
|
+
readonly code: string;
|
|
12
|
+
constructor(code: string, message: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class SmtpClient {
|
|
15
|
+
private socket;
|
|
16
|
+
private host;
|
|
17
|
+
private buffer;
|
|
18
|
+
private capabilities;
|
|
19
|
+
private responseResolve;
|
|
20
|
+
private responseReject;
|
|
21
|
+
private responseLines;
|
|
22
|
+
connect(config: SmtpClientConfig): Promise<void>;
|
|
23
|
+
ehlo(hostname: string): Promise<string[]>;
|
|
24
|
+
startTls(): Promise<void>;
|
|
25
|
+
authPlain(user: string, password: string): Promise<void>;
|
|
26
|
+
mailFrom(address: string): Promise<void>;
|
|
27
|
+
rcptTo(address: string): Promise<void>;
|
|
28
|
+
data(content: string): Promise<void>;
|
|
29
|
+
quit(): Promise<void>;
|
|
30
|
+
disconnect(): void;
|
|
31
|
+
private sendCommand;
|
|
32
|
+
private readResponse;
|
|
33
|
+
private writeRaw;
|
|
34
|
+
private onData;
|
|
35
|
+
private processBuffer;
|
|
36
|
+
private handleLine;
|
|
37
|
+
private destroySocket;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/smtp/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd;AAED,qBAAa,SAAU,SAAQ,KAAK;aAEhB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAgBD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAgB;IAEpC,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,aAAa,CAAgB;IAE/B,OAAO,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDhD,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMzC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BzB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBpC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,UAAU,IAAI,IAAI;YAMJ,WAAW;IAYzB,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,aAAa;CAQtB"}
|