gmail-workspace-mcp-server 0.1.2 → 0.2.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 +34 -6
- package/build/index.integration-with-mock.js +10 -8
- package/package.json +1 -1
- package/shared/gmail-client/lib/drafts.d.ts +2 -1
- package/shared/gmail-client/lib/mime-utils.d.ts +5 -2
- package/shared/gmail-client/lib/mime-utils.js +21 -3
- package/shared/gmail-client/lib/send-message.d.ts +2 -1
- package/shared/server.d.ts +8 -4
- package/shared/tools/draft-email.d.ts +31 -6
- package/shared/tools/draft-email.js +31 -8
- package/shared/tools/send-email.d.ts +16 -7
- package/shared/tools/send-email.js +27 -11
package/README.md
CHANGED
|
@@ -262,17 +262,32 @@ Create a draft email, optionally as a reply to an existing conversation.
|
|
|
262
262
|
|
|
263
263
|
- `to` (string, required): Recipient email address
|
|
264
264
|
- `subject` (string, required): Email subject
|
|
265
|
-
- `
|
|
265
|
+
- `plaintext_body` (string): Plain text body content (at least one of plaintext_body or html_body required)
|
|
266
|
+
- `html_body` (string): HTML body content for rich text formatting (at least one of plaintext_body or html_body required)
|
|
267
|
+
- `cc` (string, optional): CC recipients
|
|
268
|
+
- `bcc` (string, optional): BCC recipients
|
|
266
269
|
- `thread_id` (string, optional): Thread ID for replies
|
|
267
270
|
- `reply_to_email_id` (string, optional): Email ID to reply to (sets References/In-Reply-To headers)
|
|
268
271
|
|
|
269
|
-
|
|
272
|
+
At least one of `plaintext_body` or `html_body` must be provided. If both are provided, a multipart email is sent with both versions.
|
|
273
|
+
|
|
274
|
+
**Example (plain text):**
|
|
275
|
+
|
|
276
|
+
```json
|
|
277
|
+
{
|
|
278
|
+
"to": "recipient@example.com",
|
|
279
|
+
"subject": "Meeting Follow-up",
|
|
280
|
+
"plaintext_body": "Thanks for the meeting today!"
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Example (HTML):**
|
|
270
285
|
|
|
271
286
|
```json
|
|
272
287
|
{
|
|
273
288
|
"to": "recipient@example.com",
|
|
274
289
|
"subject": "Meeting Follow-up",
|
|
275
|
-
"
|
|
290
|
+
"html_body": "<p>Thanks for the meeting today! Check out <a href=\"https://example.com/notes\">the notes</a>.</p>"
|
|
276
291
|
}
|
|
277
292
|
```
|
|
278
293
|
|
|
@@ -284,18 +299,31 @@ Send an email directly or from an existing draft.
|
|
|
284
299
|
|
|
285
300
|
- `to` (string, conditional): Recipient email (required unless sending from draft)
|
|
286
301
|
- `subject` (string, conditional): Email subject (required unless sending from draft)
|
|
287
|
-
- `
|
|
302
|
+
- `plaintext_body` (string): Plain text body content (at least one of plaintext_body or html_body required, unless sending a draft)
|
|
303
|
+
- `html_body` (string): HTML body content for rich text formatting (at least one of plaintext_body or html_body required, unless sending a draft)
|
|
304
|
+
- `cc` (string, optional): CC recipients
|
|
305
|
+
- `bcc` (string, optional): BCC recipients
|
|
288
306
|
- `from_draft_id` (string, optional): Send an existing draft by ID
|
|
289
307
|
- `thread_id` (string, optional): Thread ID for replies
|
|
290
308
|
- `reply_to_email_id` (string, optional): Email ID to reply to
|
|
291
309
|
|
|
292
|
-
**Example (
|
|
310
|
+
**Example (plain text email):**
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"to": "recipient@example.com",
|
|
315
|
+
"subject": "Hello",
|
|
316
|
+
"plaintext_body": "This is a test email."
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Example (HTML email):**
|
|
293
321
|
|
|
294
322
|
```json
|
|
295
323
|
{
|
|
296
324
|
"to": "recipient@example.com",
|
|
297
325
|
"subject": "Hello",
|
|
298
|
-
"
|
|
326
|
+
"html_body": "<p>Check out <a href=\"https://example.com\">our website</a> for more details.</p>"
|
|
299
327
|
}
|
|
300
328
|
```
|
|
301
329
|
|
|
@@ -165,17 +165,18 @@ function createMockClient() {
|
|
|
165
165
|
return { ...email, labelIds: labels };
|
|
166
166
|
},
|
|
167
167
|
async createDraft(options) {
|
|
168
|
+
const bodyContent = options.plaintextBody || options.htmlBody || '';
|
|
168
169
|
const draft = {
|
|
169
170
|
id: `draft_${draftIdCounter++}`,
|
|
170
171
|
message: {
|
|
171
172
|
id: `msg_${messageIdCounter++}`,
|
|
172
173
|
threadId: options.threadId || `thread_${messageIdCounter}`,
|
|
173
174
|
labelIds: ['DRAFT'],
|
|
174
|
-
snippet:
|
|
175
|
+
snippet: bodyContent.substring(0, 100),
|
|
175
176
|
historyId: '12347',
|
|
176
177
|
internalDate: String(Date.now()),
|
|
177
178
|
payload: {
|
|
178
|
-
mimeType: 'text/plain',
|
|
179
|
+
mimeType: options.htmlBody ? 'text/html' : 'text/plain',
|
|
179
180
|
headers: [
|
|
180
181
|
{ name: 'Subject', value: options.subject },
|
|
181
182
|
{ name: 'From', value: 'me@example.com' },
|
|
@@ -183,8 +184,8 @@ function createMockClient() {
|
|
|
183
184
|
{ name: 'Date', value: new Date().toISOString() },
|
|
184
185
|
],
|
|
185
186
|
body: {
|
|
186
|
-
size:
|
|
187
|
-
data: Buffer.from(
|
|
187
|
+
size: bodyContent.length,
|
|
188
|
+
data: Buffer.from(bodyContent).toString('base64url'),
|
|
188
189
|
},
|
|
189
190
|
},
|
|
190
191
|
},
|
|
@@ -221,15 +222,16 @@ function createMockClient() {
|
|
|
221
222
|
mockDrafts.splice(index, 1);
|
|
222
223
|
},
|
|
223
224
|
async sendMessage(options) {
|
|
225
|
+
const bodyContent = options.plaintextBody || options.htmlBody || '';
|
|
224
226
|
const sentMessage = {
|
|
225
227
|
id: `msg_${messageIdCounter++}`,
|
|
226
228
|
threadId: options.threadId || `thread_${messageIdCounter}`,
|
|
227
229
|
labelIds: ['SENT'],
|
|
228
|
-
snippet:
|
|
230
|
+
snippet: bodyContent.substring(0, 100),
|
|
229
231
|
historyId: '12348',
|
|
230
232
|
internalDate: String(Date.now()),
|
|
231
233
|
payload: {
|
|
232
|
-
mimeType: 'text/plain',
|
|
234
|
+
mimeType: options.htmlBody ? 'text/html' : 'text/plain',
|
|
233
235
|
headers: [
|
|
234
236
|
{ name: 'Subject', value: options.subject },
|
|
235
237
|
{ name: 'From', value: 'me@example.com' },
|
|
@@ -237,8 +239,8 @@ function createMockClient() {
|
|
|
237
239
|
{ name: 'Date', value: new Date().toISOString() },
|
|
238
240
|
],
|
|
239
241
|
body: {
|
|
240
|
-
size:
|
|
241
|
-
data: Buffer.from(
|
|
242
|
+
size: bodyContent.length,
|
|
243
|
+
data: Buffer.from(bodyContent).toString('base64url'),
|
|
242
244
|
},
|
|
243
245
|
},
|
|
244
246
|
};
|
package/package.json
CHANGED
|
@@ -13,7 +13,8 @@ interface DraftListItem {
|
|
|
13
13
|
export declare function createDraft(baseUrl: string, headers: Record<string, string>, from: string, options: {
|
|
14
14
|
to: string;
|
|
15
15
|
subject: string;
|
|
16
|
-
|
|
16
|
+
plaintextBody?: string;
|
|
17
|
+
htmlBody?: string;
|
|
17
18
|
cc?: string;
|
|
18
19
|
bcc?: string;
|
|
19
20
|
threadId?: string;
|
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
export interface MimeMessageOptions {
|
|
5
5
|
to: string;
|
|
6
6
|
subject: string;
|
|
7
|
-
|
|
7
|
+
plaintextBody?: string;
|
|
8
|
+
htmlBody?: string;
|
|
8
9
|
cc?: string;
|
|
9
10
|
bcc?: string;
|
|
10
11
|
inReplyTo?: string;
|
|
11
12
|
references?: string;
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
|
-
* Builds a MIME message from email options
|
|
15
|
+
* Builds a MIME message from email options.
|
|
16
|
+
* If both plaintextBody and htmlBody are provided, creates a multipart/alternative message.
|
|
17
|
+
* If only one is provided, creates a single-part message with the appropriate content type.
|
|
15
18
|
*/
|
|
16
19
|
export declare function buildMimeMessage(from: string, options: MimeMessageOptions): string;
|
|
17
20
|
/**
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* MIME message utilities for building and encoding email messages
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Builds a MIME message from email options
|
|
5
|
+
* Builds a MIME message from email options.
|
|
6
|
+
* If both plaintextBody and htmlBody are provided, creates a multipart/alternative message.
|
|
7
|
+
* If only one is provided, creates a single-part message with the appropriate content type.
|
|
6
8
|
*/
|
|
7
9
|
export function buildMimeMessage(from, options) {
|
|
8
10
|
const headers = [
|
|
@@ -10,7 +12,6 @@ export function buildMimeMessage(from, options) {
|
|
|
10
12
|
`To: ${options.to}`,
|
|
11
13
|
`Subject: ${options.subject}`,
|
|
12
14
|
'MIME-Version: 1.0',
|
|
13
|
-
'Content-Type: text/plain; charset=utf-8',
|
|
14
15
|
];
|
|
15
16
|
if (options.cc) {
|
|
16
17
|
headers.push(`Cc: ${options.cc}`);
|
|
@@ -24,7 +25,24 @@ export function buildMimeMessage(from, options) {
|
|
|
24
25
|
if (options.references) {
|
|
25
26
|
headers.push(`References: ${options.references}`);
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
// If both plain text and HTML are provided, use multipart/alternative
|
|
29
|
+
if (options.plaintextBody && options.htmlBody) {
|
|
30
|
+
const boundary = `boundary_${Date.now()}_${Math.random().toString(36).substring(2)}`;
|
|
31
|
+
headers.push(`Content-Type: multipart/alternative; boundary="${boundary}"`);
|
|
32
|
+
const parts = [
|
|
33
|
+
`--${boundary}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${options.plaintextBody}`,
|
|
34
|
+
`--${boundary}\r\nContent-Type: text/html; charset=utf-8\r\n\r\n${options.htmlBody}`,
|
|
35
|
+
`--${boundary}--`,
|
|
36
|
+
];
|
|
37
|
+
return headers.join('\r\n') + '\r\n\r\n' + parts.join('\r\n');
|
|
38
|
+
}
|
|
39
|
+
// Single content type
|
|
40
|
+
if (options.htmlBody) {
|
|
41
|
+
headers.push('Content-Type: text/html; charset=utf-8');
|
|
42
|
+
return headers.join('\r\n') + '\r\n\r\n' + options.htmlBody;
|
|
43
|
+
}
|
|
44
|
+
headers.push('Content-Type: text/plain; charset=utf-8');
|
|
45
|
+
return headers.join('\r\n') + '\r\n\r\n' + (options.plaintextBody ?? '');
|
|
28
46
|
}
|
|
29
47
|
/**
|
|
30
48
|
* Converts a string to base64url encoding (RFC 4648)
|
|
@@ -5,7 +5,8 @@ import type { Email } from '../../types.js';
|
|
|
5
5
|
export declare function sendMessage(baseUrl: string, headers: Record<string, string>, from: string, options: {
|
|
6
6
|
to: string;
|
|
7
7
|
subject: string;
|
|
8
|
-
|
|
8
|
+
plaintextBody?: string;
|
|
9
|
+
htmlBody?: string;
|
|
9
10
|
cc?: string;
|
|
10
11
|
bcc?: string;
|
|
11
12
|
threadId?: string;
|
package/shared/server.d.ts
CHANGED
|
@@ -50,7 +50,8 @@ export interface IGmailClient {
|
|
|
50
50
|
createDraft(options: {
|
|
51
51
|
to: string;
|
|
52
52
|
subject: string;
|
|
53
|
-
|
|
53
|
+
plaintextBody?: string;
|
|
54
|
+
htmlBody?: string;
|
|
54
55
|
cc?: string;
|
|
55
56
|
bcc?: string;
|
|
56
57
|
threadId?: string;
|
|
@@ -85,7 +86,8 @@ export interface IGmailClient {
|
|
|
85
86
|
sendMessage(options: {
|
|
86
87
|
to: string;
|
|
87
88
|
subject: string;
|
|
88
|
-
|
|
89
|
+
plaintextBody?: string;
|
|
90
|
+
htmlBody?: string;
|
|
89
91
|
cc?: string;
|
|
90
92
|
bcc?: string;
|
|
91
93
|
threadId?: string;
|
|
@@ -167,7 +169,8 @@ declare abstract class BaseGmailClient implements IGmailClient {
|
|
|
167
169
|
createDraft(options: {
|
|
168
170
|
to: string;
|
|
169
171
|
subject: string;
|
|
170
|
-
|
|
172
|
+
plaintextBody?: string;
|
|
173
|
+
htmlBody?: string;
|
|
171
174
|
cc?: string;
|
|
172
175
|
bcc?: string;
|
|
173
176
|
threadId?: string;
|
|
@@ -190,7 +193,8 @@ declare abstract class BaseGmailClient implements IGmailClient {
|
|
|
190
193
|
sendMessage(options: {
|
|
191
194
|
to: string;
|
|
192
195
|
subject: string;
|
|
193
|
-
|
|
196
|
+
plaintextBody?: string;
|
|
197
|
+
htmlBody?: string;
|
|
194
198
|
cc?: string;
|
|
195
199
|
bcc?: string;
|
|
196
200
|
threadId?: string;
|
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { ClientFactory } from '../server.js';
|
|
4
|
-
export declare const DraftEmailSchema: z.ZodObject<{
|
|
4
|
+
export declare const DraftEmailSchema: z.ZodEffects<z.ZodObject<{
|
|
5
5
|
to: z.ZodString;
|
|
6
6
|
subject: z.ZodString;
|
|
7
|
-
|
|
7
|
+
plaintext_body: z.ZodOptional<z.ZodString>;
|
|
8
|
+
html_body: z.ZodOptional<z.ZodString>;
|
|
8
9
|
cc: z.ZodOptional<z.ZodString>;
|
|
9
10
|
bcc: z.ZodOptional<z.ZodString>;
|
|
10
11
|
thread_id: z.ZodOptional<z.ZodString>;
|
|
11
12
|
reply_to_email_id: z.ZodOptional<z.ZodString>;
|
|
12
13
|
}, "strip", z.ZodTypeAny, {
|
|
13
|
-
body: string;
|
|
14
14
|
to: string;
|
|
15
15
|
subject: string;
|
|
16
|
+
plaintext_body?: string | undefined;
|
|
17
|
+
html_body?: string | undefined;
|
|
16
18
|
cc?: string | undefined;
|
|
17
19
|
bcc?: string | undefined;
|
|
18
20
|
thread_id?: string | undefined;
|
|
19
21
|
reply_to_email_id?: string | undefined;
|
|
20
22
|
}, {
|
|
21
|
-
body: string;
|
|
22
23
|
to: string;
|
|
23
24
|
subject: string;
|
|
25
|
+
plaintext_body?: string | undefined;
|
|
26
|
+
html_body?: string | undefined;
|
|
27
|
+
cc?: string | undefined;
|
|
28
|
+
bcc?: string | undefined;
|
|
29
|
+
thread_id?: string | undefined;
|
|
30
|
+
reply_to_email_id?: string | undefined;
|
|
31
|
+
}>, {
|
|
32
|
+
to: string;
|
|
33
|
+
subject: string;
|
|
34
|
+
plaintext_body?: string | undefined;
|
|
35
|
+
html_body?: string | undefined;
|
|
36
|
+
cc?: string | undefined;
|
|
37
|
+
bcc?: string | undefined;
|
|
38
|
+
thread_id?: string | undefined;
|
|
39
|
+
reply_to_email_id?: string | undefined;
|
|
40
|
+
}, {
|
|
41
|
+
to: string;
|
|
42
|
+
subject: string;
|
|
43
|
+
plaintext_body?: string | undefined;
|
|
44
|
+
html_body?: string | undefined;
|
|
24
45
|
cc?: string | undefined;
|
|
25
46
|
bcc?: string | undefined;
|
|
26
47
|
thread_id?: string | undefined;
|
|
@@ -40,9 +61,13 @@ export declare function draftEmailTool(server: Server, clientFactory: ClientFact
|
|
|
40
61
|
type: string;
|
|
41
62
|
description: "Subject line of the email.";
|
|
42
63
|
};
|
|
43
|
-
|
|
64
|
+
plaintext_body: {
|
|
65
|
+
type: string;
|
|
66
|
+
description: "Plain text body content of the email. At least one of plaintext_body or html_body must be provided. If both are provided, a multipart email is sent with both versions.";
|
|
67
|
+
};
|
|
68
|
+
html_body: {
|
|
44
69
|
type: string;
|
|
45
|
-
description: "
|
|
70
|
+
description: "HTML body content of the email for rich text formatting (links, bold, lists, etc.). At least one of plaintext_body or html_body must be provided. If both are provided, a multipart email is sent with both versions.";
|
|
46
71
|
};
|
|
47
72
|
cc: {
|
|
48
73
|
type: string;
|
|
@@ -3,7 +3,8 @@ import { getHeader } from '../utils/email-helpers.js';
|
|
|
3
3
|
const PARAM_DESCRIPTIONS = {
|
|
4
4
|
to: 'Recipient email address(es). For multiple recipients, separate with commas.',
|
|
5
5
|
subject: 'Subject line of the email.',
|
|
6
|
-
|
|
6
|
+
plaintext_body: 'Plain text body content of the email. At least one of plaintext_body or html_body must be provided. If both are provided, a multipart email is sent with both versions.',
|
|
7
|
+
html_body: 'HTML body content of the email for rich text formatting (links, bold, lists, etc.). At least one of plaintext_body or html_body must be provided. If both are provided, a multipart email is sent with both versions.',
|
|
7
8
|
cc: 'CC recipient email address(es). For multiple, separate with commas.',
|
|
8
9
|
bcc: 'BCC recipient email address(es). For multiple, separate with commas.',
|
|
9
10
|
thread_id: 'Thread ID to add this draft to an existing conversation. ' +
|
|
@@ -11,26 +12,37 @@ const PARAM_DESCRIPTIONS = {
|
|
|
11
12
|
reply_to_email_id: 'Email ID to reply to. If provided, the draft will be formatted as a reply ' +
|
|
12
13
|
'with proper In-Reply-To and References headers. Also requires thread_id.',
|
|
13
14
|
};
|
|
14
|
-
export const DraftEmailSchema = z
|
|
15
|
+
export const DraftEmailSchema = z
|
|
16
|
+
.object({
|
|
15
17
|
to: z.string().min(1).describe(PARAM_DESCRIPTIONS.to),
|
|
16
18
|
subject: z.string().min(1).describe(PARAM_DESCRIPTIONS.subject),
|
|
17
|
-
|
|
19
|
+
plaintext_body: z.string().min(1).optional().describe(PARAM_DESCRIPTIONS.plaintext_body),
|
|
20
|
+
html_body: z.string().min(1).optional().describe(PARAM_DESCRIPTIONS.html_body),
|
|
18
21
|
cc: z.string().optional().describe(PARAM_DESCRIPTIONS.cc),
|
|
19
22
|
bcc: z.string().optional().describe(PARAM_DESCRIPTIONS.bcc),
|
|
20
23
|
thread_id: z.string().optional().describe(PARAM_DESCRIPTIONS.thread_id),
|
|
21
24
|
reply_to_email_id: z.string().optional().describe(PARAM_DESCRIPTIONS.reply_to_email_id),
|
|
25
|
+
})
|
|
26
|
+
.refine((data) => {
|
|
27
|
+
return Boolean(data.plaintext_body) || Boolean(data.html_body);
|
|
28
|
+
}, {
|
|
29
|
+
message: 'At least one of plaintext_body or html_body must be provided.',
|
|
22
30
|
});
|
|
23
31
|
const TOOL_DESCRIPTION = `Create a draft email that can be reviewed and sent later.
|
|
24
32
|
|
|
25
33
|
**Parameters:**
|
|
26
34
|
- to: Recipient email address(es) (required)
|
|
27
35
|
- subject: Email subject line (required)
|
|
28
|
-
-
|
|
36
|
+
- plaintext_body: Plain text body content (at least one of plaintext_body or html_body required)
|
|
37
|
+
- html_body: HTML body content for rich text formatting (at least one of plaintext_body or html_body required)
|
|
29
38
|
- cc: CC recipients (optional)
|
|
30
39
|
- bcc: BCC recipients (optional)
|
|
31
40
|
- thread_id: Thread ID to reply to an existing conversation (optional)
|
|
32
41
|
- reply_to_email_id: Email ID to reply to, sets proper reply headers (optional)
|
|
33
42
|
|
|
43
|
+
**Body content:**
|
|
44
|
+
At least one of plaintext_body or html_body must be provided. If both are provided, a multipart email is sent with both plain text and HTML versions. Use html_body for rich formatting like hyperlinks, bold text, or lists.
|
|
45
|
+
|
|
34
46
|
**Creating a reply:**
|
|
35
47
|
To create a draft reply to an existing email:
|
|
36
48
|
1. Get the thread_id and email_id from get_email_conversation
|
|
@@ -57,9 +69,13 @@ export function draftEmailTool(server, clientFactory) {
|
|
|
57
69
|
type: 'string',
|
|
58
70
|
description: PARAM_DESCRIPTIONS.subject,
|
|
59
71
|
},
|
|
60
|
-
|
|
72
|
+
plaintext_body: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
description: PARAM_DESCRIPTIONS.plaintext_body,
|
|
75
|
+
},
|
|
76
|
+
html_body: {
|
|
61
77
|
type: 'string',
|
|
62
|
-
description: PARAM_DESCRIPTIONS.
|
|
78
|
+
description: PARAM_DESCRIPTIONS.html_body,
|
|
63
79
|
},
|
|
64
80
|
cc: {
|
|
65
81
|
type: 'string',
|
|
@@ -78,7 +94,7 @@ export function draftEmailTool(server, clientFactory) {
|
|
|
78
94
|
description: PARAM_DESCRIPTIONS.reply_to_email_id,
|
|
79
95
|
},
|
|
80
96
|
},
|
|
81
|
-
required: ['to', 'subject'
|
|
97
|
+
required: ['to', 'subject'],
|
|
82
98
|
},
|
|
83
99
|
handler: async (args) => {
|
|
84
100
|
try {
|
|
@@ -103,7 +119,8 @@ export function draftEmailTool(server, clientFactory) {
|
|
|
103
119
|
const draft = await client.createDraft({
|
|
104
120
|
to: parsed.to,
|
|
105
121
|
subject: parsed.subject,
|
|
106
|
-
|
|
122
|
+
plaintextBody: parsed.plaintext_body,
|
|
123
|
+
htmlBody: parsed.html_body,
|
|
107
124
|
cc: parsed.cc,
|
|
108
125
|
bcc: parsed.bcc,
|
|
109
126
|
threadId: parsed.thread_id,
|
|
@@ -117,6 +134,12 @@ export function draftEmailTool(server, clientFactory) {
|
|
|
117
134
|
}
|
|
118
135
|
responseText += `\n\n**To:** ${parsed.to}`;
|
|
119
136
|
responseText += `\n**Subject:** ${parsed.subject}`;
|
|
137
|
+
const format = parsed.plaintext_body && parsed.html_body
|
|
138
|
+
? 'Multipart (plain text + HTML)'
|
|
139
|
+
: parsed.html_body
|
|
140
|
+
? 'HTML'
|
|
141
|
+
: 'Plain text';
|
|
142
|
+
responseText += `\n**Format:** ${format}`;
|
|
120
143
|
if (parsed.cc) {
|
|
121
144
|
responseText += `\n**CC:** ${parsed.cc}`;
|
|
122
145
|
}
|
|
@@ -4,43 +4,48 @@ import type { ClientFactory } from '../server.js';
|
|
|
4
4
|
export declare const SendEmailSchema: z.ZodEffects<z.ZodObject<{
|
|
5
5
|
to: z.ZodOptional<z.ZodString>;
|
|
6
6
|
subject: z.ZodOptional<z.ZodString>;
|
|
7
|
-
|
|
7
|
+
plaintext_body: z.ZodOptional<z.ZodString>;
|
|
8
|
+
html_body: z.ZodOptional<z.ZodString>;
|
|
8
9
|
cc: z.ZodOptional<z.ZodString>;
|
|
9
10
|
bcc: z.ZodOptional<z.ZodString>;
|
|
10
11
|
thread_id: z.ZodOptional<z.ZodString>;
|
|
11
12
|
reply_to_email_id: z.ZodOptional<z.ZodString>;
|
|
12
13
|
from_draft_id: z.ZodOptional<z.ZodString>;
|
|
13
14
|
}, "strip", z.ZodTypeAny, {
|
|
14
|
-
body?: string | undefined;
|
|
15
15
|
to?: string | undefined;
|
|
16
16
|
subject?: string | undefined;
|
|
17
|
+
plaintext_body?: string | undefined;
|
|
18
|
+
html_body?: string | undefined;
|
|
17
19
|
cc?: string | undefined;
|
|
18
20
|
bcc?: string | undefined;
|
|
19
21
|
thread_id?: string | undefined;
|
|
20
22
|
reply_to_email_id?: string | undefined;
|
|
21
23
|
from_draft_id?: string | undefined;
|
|
22
24
|
}, {
|
|
23
|
-
body?: string | undefined;
|
|
24
25
|
to?: string | undefined;
|
|
25
26
|
subject?: string | undefined;
|
|
27
|
+
plaintext_body?: string | undefined;
|
|
28
|
+
html_body?: string | undefined;
|
|
26
29
|
cc?: string | undefined;
|
|
27
30
|
bcc?: string | undefined;
|
|
28
31
|
thread_id?: string | undefined;
|
|
29
32
|
reply_to_email_id?: string | undefined;
|
|
30
33
|
from_draft_id?: string | undefined;
|
|
31
34
|
}>, {
|
|
32
|
-
body?: string | undefined;
|
|
33
35
|
to?: string | undefined;
|
|
34
36
|
subject?: string | undefined;
|
|
37
|
+
plaintext_body?: string | undefined;
|
|
38
|
+
html_body?: string | undefined;
|
|
35
39
|
cc?: string | undefined;
|
|
36
40
|
bcc?: string | undefined;
|
|
37
41
|
thread_id?: string | undefined;
|
|
38
42
|
reply_to_email_id?: string | undefined;
|
|
39
43
|
from_draft_id?: string | undefined;
|
|
40
44
|
}, {
|
|
41
|
-
body?: string | undefined;
|
|
42
45
|
to?: string | undefined;
|
|
43
46
|
subject?: string | undefined;
|
|
47
|
+
plaintext_body?: string | undefined;
|
|
48
|
+
html_body?: string | undefined;
|
|
44
49
|
cc?: string | undefined;
|
|
45
50
|
bcc?: string | undefined;
|
|
46
51
|
thread_id?: string | undefined;
|
|
@@ -61,9 +66,13 @@ export declare function sendEmailTool(server: Server, clientFactory: ClientFacto
|
|
|
61
66
|
type: string;
|
|
62
67
|
description: "Subject line of the email.";
|
|
63
68
|
};
|
|
64
|
-
|
|
69
|
+
plaintext_body: {
|
|
65
70
|
type: string;
|
|
66
|
-
description: "Plain text body content of the email.";
|
|
71
|
+
description: "Plain text body content of the email. At least one of plaintext_body or html_body must be provided (unless sending a draft). If both are provided, a multipart email is sent with both versions.";
|
|
72
|
+
};
|
|
73
|
+
html_body: {
|
|
74
|
+
type: string;
|
|
75
|
+
description: "HTML body content of the email for rich text formatting (links, bold, lists, etc.). At least one of plaintext_body or html_body must be provided (unless sending a draft). If both are provided, a multipart email is sent with both versions.";
|
|
67
76
|
};
|
|
68
77
|
cc: {
|
|
69
78
|
type: string;
|
|
@@ -3,7 +3,8 @@ import { getHeader } from '../utils/email-helpers.js';
|
|
|
3
3
|
const PARAM_DESCRIPTIONS = {
|
|
4
4
|
to: 'Recipient email address(es). For multiple recipients, separate with commas.',
|
|
5
5
|
subject: 'Subject line of the email.',
|
|
6
|
-
|
|
6
|
+
plaintext_body: 'Plain text body content of the email. At least one of plaintext_body or html_body must be provided (unless sending a draft). If both are provided, a multipart email is sent with both versions.',
|
|
7
|
+
html_body: 'HTML body content of the email for rich text formatting (links, bold, lists, etc.). At least one of plaintext_body or html_body must be provided (unless sending a draft). If both are provided, a multipart email is sent with both versions.',
|
|
7
8
|
cc: 'CC recipient email address(es). For multiple, separate with commas.',
|
|
8
9
|
bcc: 'BCC recipient email address(es). For multiple, separate with commas.',
|
|
9
10
|
thread_id: 'Thread ID to add this email to an existing conversation. ' +
|
|
@@ -11,13 +12,14 @@ const PARAM_DESCRIPTIONS = {
|
|
|
11
12
|
reply_to_email_id: 'Email ID to reply to. If provided, the email will be formatted as a reply ' +
|
|
12
13
|
'with proper In-Reply-To and References headers. Also requires thread_id.',
|
|
13
14
|
from_draft_id: 'Draft ID to send. If provided, sends the specified draft instead of composing a new email. ' +
|
|
14
|
-
'When using this, other parameters (to, subject,
|
|
15
|
+
'When using this, other parameters (to, subject, plaintext_body, etc.) are ignored.',
|
|
15
16
|
};
|
|
16
17
|
export const SendEmailSchema = z
|
|
17
18
|
.object({
|
|
18
19
|
to: z.string().optional().describe(PARAM_DESCRIPTIONS.to),
|
|
19
20
|
subject: z.string().optional().describe(PARAM_DESCRIPTIONS.subject),
|
|
20
|
-
|
|
21
|
+
plaintext_body: z.string().min(1).optional().describe(PARAM_DESCRIPTIONS.plaintext_body),
|
|
22
|
+
html_body: z.string().min(1).optional().describe(PARAM_DESCRIPTIONS.html_body),
|
|
21
23
|
cc: z.string().optional().describe(PARAM_DESCRIPTIONS.cc),
|
|
22
24
|
bcc: z.string().optional().describe(PARAM_DESCRIPTIONS.bcc),
|
|
23
25
|
thread_id: z.string().optional().describe(PARAM_DESCRIPTIONS.thread_id),
|
|
@@ -25,20 +27,21 @@ export const SendEmailSchema = z
|
|
|
25
27
|
from_draft_id: z.string().optional().describe(PARAM_DESCRIPTIONS.from_draft_id),
|
|
26
28
|
})
|
|
27
29
|
.refine((data) => {
|
|
28
|
-
// Either from_draft_id is provided, OR to, subject, and
|
|
30
|
+
// Either from_draft_id is provided, OR to, subject, and one of plaintext_body/html_body are all provided
|
|
29
31
|
if (data.from_draft_id) {
|
|
30
32
|
return true;
|
|
31
33
|
}
|
|
32
|
-
return data.to && data.subject && data.
|
|
34
|
+
return data.to && data.subject && (data.plaintext_body || data.html_body);
|
|
33
35
|
}, {
|
|
34
|
-
message: 'Either provide from_draft_id to send a draft, or provide to, subject, and
|
|
36
|
+
message: 'Either provide from_draft_id to send a draft, or provide to, subject, and at least one of plaintext_body or html_body to send a new email.',
|
|
35
37
|
});
|
|
36
38
|
const TOOL_DESCRIPTION = `Send an email immediately or send a previously created draft.
|
|
37
39
|
|
|
38
40
|
**Option 1: Send a new email**
|
|
39
41
|
- to: Recipient email address(es) (required)
|
|
40
42
|
- subject: Email subject line (required)
|
|
41
|
-
-
|
|
43
|
+
- plaintext_body: Plain text body content (at least one of plaintext_body or html_body required)
|
|
44
|
+
- html_body: HTML body content for rich text formatting (at least one of plaintext_body or html_body required)
|
|
42
45
|
- cc: CC recipients (optional)
|
|
43
46
|
- bcc: BCC recipients (optional)
|
|
44
47
|
- thread_id: Thread ID to reply to an existing conversation (optional)
|
|
@@ -47,6 +50,9 @@ const TOOL_DESCRIPTION = `Send an email immediately or send a previously created
|
|
|
47
50
|
**Option 2: Send a draft**
|
|
48
51
|
- from_draft_id: ID of the draft to send (all other parameters are ignored)
|
|
49
52
|
|
|
53
|
+
**Body content:**
|
|
54
|
+
At least one of plaintext_body or html_body must be provided. If both are provided, a multipart email is sent with both plain text and HTML versions. Use html_body for rich formatting like hyperlinks, bold text, or lists.
|
|
55
|
+
|
|
50
56
|
**Sending a reply:**
|
|
51
57
|
To send a reply to an existing email:
|
|
52
58
|
1. Get the thread_id and email_id from get_email_conversation
|
|
@@ -73,9 +79,13 @@ export function sendEmailTool(server, clientFactory) {
|
|
|
73
79
|
type: 'string',
|
|
74
80
|
description: PARAM_DESCRIPTIONS.subject,
|
|
75
81
|
},
|
|
76
|
-
|
|
82
|
+
plaintext_body: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: PARAM_DESCRIPTIONS.plaintext_body,
|
|
85
|
+
},
|
|
86
|
+
html_body: {
|
|
77
87
|
type: 'string',
|
|
78
|
-
description: PARAM_DESCRIPTIONS.
|
|
88
|
+
description: PARAM_DESCRIPTIONS.html_body,
|
|
79
89
|
},
|
|
80
90
|
cc: {
|
|
81
91
|
type: 'string',
|
|
@@ -120,7 +130,6 @@ export function sendEmailTool(server, clientFactory) {
|
|
|
120
130
|
// TypeScript knows these are defined due to the refine check
|
|
121
131
|
const to = parsed.to;
|
|
122
132
|
const subject = parsed.subject;
|
|
123
|
-
const body = parsed.body;
|
|
124
133
|
let inReplyTo;
|
|
125
134
|
let references;
|
|
126
135
|
// If replying to an email, get the Message-ID for proper threading
|
|
@@ -140,7 +149,8 @@ export function sendEmailTool(server, clientFactory) {
|
|
|
140
149
|
const sentEmail = await client.sendMessage({
|
|
141
150
|
to,
|
|
142
151
|
subject,
|
|
143
|
-
|
|
152
|
+
plaintextBody: parsed.plaintext_body,
|
|
153
|
+
htmlBody: parsed.html_body,
|
|
144
154
|
cc: parsed.cc,
|
|
145
155
|
bcc: parsed.bcc,
|
|
146
156
|
threadId: parsed.thread_id,
|
|
@@ -153,6 +163,12 @@ export function sendEmailTool(server, clientFactory) {
|
|
|
153
163
|
}
|
|
154
164
|
responseText += `\n\n**To:** ${to}`;
|
|
155
165
|
responseText += `\n**Subject:** ${subject}`;
|
|
166
|
+
const format = parsed.plaintext_body && parsed.html_body
|
|
167
|
+
? 'Multipart (plain text + HTML)'
|
|
168
|
+
: parsed.html_body
|
|
169
|
+
? 'HTML'
|
|
170
|
+
: 'Plain text';
|
|
171
|
+
responseText += `\n**Format:** ${format}`;
|
|
156
172
|
if (parsed.cc) {
|
|
157
173
|
responseText += `\n**CC:** ${parsed.cc}`;
|
|
158
174
|
}
|