@agenticmail/enterprise 0.5.316 → 0.5.318
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/dist/agent-tools-263HM5QU.js +13949 -0
- package/dist/agent-tools-AT4D276V.js +13949 -0
- package/dist/chunk-36XNMIHA.js +5087 -0
- package/dist/chunk-6G5SXLXC.js +4921 -0
- package/dist/chunk-6PWDS7KY.js +5087 -0
- package/dist/chunk-D24JY75H.js +1519 -0
- package/dist/chunk-MMYBDHDB.js +4921 -0
- package/dist/chunk-OW4GLBHP.js +1519 -0
- package/dist/cli-agent-FNMDJN7T.js +2357 -0
- package/dist/cli-agent-ZSHUPBBN.js +2357 -0
- package/dist/cli-serve-DTQLN5UI.js +140 -0
- package/dist/cli-serve-LNTT73P2.js +140 -0
- package/dist/cli.js +3 -3
- package/dist/index.js +17 -17
- package/dist/integrations-TF4EBCJ7.js +43830 -0
- package/dist/microsoft-HPLA5ZL5.js +2414 -0
- package/dist/microsoft-UFLZBEAC.js +1619 -0
- package/dist/runtime-HTIM7GZR.js +45 -0
- package/dist/runtime-QQ6LAY4U.js +45 -0
- package/dist/server-DFR7FI3Q.js +28 -0
- package/dist/server-TXV3ZVVR.js +28 -0
- package/dist/setup-ADSKKBGV.js +20 -0
- package/dist/setup-LW4MLU2N.js +20 -0
- package/package.json +1 -1
- package/src/agent-tools/index.ts +7 -2
- package/src/agent-tools/tools/microsoft/contacts.ts +176 -0
- package/src/agent-tools/tools/microsoft/excel.ts +261 -0
- package/src/agent-tools/tools/microsoft/graph-api.ts +50 -0
- package/src/agent-tools/tools/microsoft/index.ts +79 -0
- package/src/agent-tools/tools/microsoft/onedrive.ts +228 -0
- package/src/agent-tools/tools/microsoft/onenote.ts +186 -0
- package/src/agent-tools/tools/microsoft/outlook-calendar.ts +286 -0
- package/src/agent-tools/tools/microsoft/outlook-mail.ts +431 -0
- package/src/agent-tools/tools/microsoft/sharepoint.ts +328 -0
- package/src/agent-tools/tools/microsoft/teams.ts +244 -0
- package/src/agent-tools/tools/microsoft/todo.ts +181 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft Outlook Mail Tools
|
|
3
|
+
*
|
|
4
|
+
* Full Outlook/Exchange mail management via Microsoft Graph API.
|
|
5
|
+
* Covers inbox, send, reply, forward, drafts, folders, attachments, search.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AnyAgentTool, ToolCreationOptions } from '../../types.js';
|
|
9
|
+
import { jsonResult, errorResult } from '../../common.js';
|
|
10
|
+
import type { MicrosoftToolsConfig } from './index.js';
|
|
11
|
+
import { graph } from './graph-api.js';
|
|
12
|
+
|
|
13
|
+
export function createOutlookMailTools(config: MicrosoftToolsConfig, _options?: ToolCreationOptions): AnyAgentTool[] {
|
|
14
|
+
const tp = config.tokenProvider;
|
|
15
|
+
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
name: 'outlook_mail_list',
|
|
19
|
+
description: 'List messages from Outlook mailbox. Returns recent emails from inbox or specified folder.',
|
|
20
|
+
category: 'utility' as const,
|
|
21
|
+
parameters: {
|
|
22
|
+
type: 'object' as const,
|
|
23
|
+
properties: {
|
|
24
|
+
folder: { type: 'string', description: 'Folder: inbox, sentitems, drafts, deleteditems, junkemail, or folder ID (default: inbox)' },
|
|
25
|
+
maxResults: { type: 'number', description: 'Max messages to return (default: 20, max: 50)' },
|
|
26
|
+
filter: { type: 'string', description: 'OData $filter expression (e.g., "isRead eq false", "from/emailAddress/address eq \'user@example.com\'")' },
|
|
27
|
+
search: { type: 'string', description: 'Search query (searches subject, body, sender)' },
|
|
28
|
+
},
|
|
29
|
+
required: [],
|
|
30
|
+
},
|
|
31
|
+
async execute(_id: string, params: any) {
|
|
32
|
+
try {
|
|
33
|
+
const token = await tp.getAccessToken();
|
|
34
|
+
const folder = params.folder || 'inbox';
|
|
35
|
+
const top = Math.min(params.maxResults || 20, 50);
|
|
36
|
+
const query: Record<string, string> = {
|
|
37
|
+
'$top': String(top),
|
|
38
|
+
'$orderby': 'receivedDateTime desc',
|
|
39
|
+
'$select': 'id,subject,from,toRecipients,ccRecipients,receivedDateTime,isRead,hasAttachments,importance,bodyPreview,flag,conversationId',
|
|
40
|
+
};
|
|
41
|
+
if (params.filter) query['$filter'] = params.filter;
|
|
42
|
+
if (params.search) query['$search'] = `"${params.search}"`;
|
|
43
|
+
|
|
44
|
+
const data = await graph(token, `/me/mailFolders/${folder}/messages`, { query });
|
|
45
|
+
const messages = (data.value || []).map((m: any) => ({
|
|
46
|
+
id: m.id,
|
|
47
|
+
subject: m.subject,
|
|
48
|
+
from: m.from?.emailAddress?.address,
|
|
49
|
+
fromName: m.from?.emailAddress?.name,
|
|
50
|
+
to: m.toRecipients?.map((r: any) => r.emailAddress?.address),
|
|
51
|
+
cc: m.ccRecipients?.map((r: any) => r.emailAddress?.address),
|
|
52
|
+
date: m.receivedDateTime,
|
|
53
|
+
isRead: m.isRead,
|
|
54
|
+
hasAttachments: m.hasAttachments,
|
|
55
|
+
importance: m.importance,
|
|
56
|
+
preview: m.bodyPreview,
|
|
57
|
+
flagged: m.flag?.flagStatus === 'flagged',
|
|
58
|
+
conversationId: m.conversationId,
|
|
59
|
+
}));
|
|
60
|
+
return jsonResult({ messages, count: messages.length });
|
|
61
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
{
|
|
66
|
+
name: 'outlook_mail_read',
|
|
67
|
+
description: 'Read a specific email message by ID. Returns full body, headers, and attachment list.',
|
|
68
|
+
category: 'utility' as const,
|
|
69
|
+
parameters: {
|
|
70
|
+
type: 'object' as const,
|
|
71
|
+
properties: {
|
|
72
|
+
messageId: { type: 'string', description: 'Message ID to read' },
|
|
73
|
+
markAsRead: { type: 'boolean', description: 'Mark as read when opening (default: true)' },
|
|
74
|
+
},
|
|
75
|
+
required: ['messageId'],
|
|
76
|
+
},
|
|
77
|
+
async execute(_id: string, params: any) {
|
|
78
|
+
try {
|
|
79
|
+
const token = await tp.getAccessToken();
|
|
80
|
+
const msg = await graph(token, `/me/messages/${params.messageId}`, {
|
|
81
|
+
query: { '$select': 'id,subject,from,toRecipients,ccRecipients,bccRecipients,replyTo,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,body,flag,conversationId,internetMessageId,parentFolderId' }
|
|
82
|
+
});
|
|
83
|
+
// Mark as read
|
|
84
|
+
if (params.markAsRead !== false && !msg.isRead) {
|
|
85
|
+
graph(token, `/me/messages/${params.messageId}`, { method: 'PATCH', body: { isRead: true } }).catch(() => {});
|
|
86
|
+
}
|
|
87
|
+
// Get attachments if any
|
|
88
|
+
let attachments: any[] = [];
|
|
89
|
+
if (msg.hasAttachments) {
|
|
90
|
+
const att = await graph(token, `/me/messages/${params.messageId}/attachments`, {
|
|
91
|
+
query: { '$select': 'id,name,contentType,size,isInline' }
|
|
92
|
+
});
|
|
93
|
+
attachments = (att.value || []).map((a: any) => ({
|
|
94
|
+
id: a.id, name: a.name, contentType: a.contentType,
|
|
95
|
+
size: a.size, isInline: a.isInline,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
return jsonResult({
|
|
99
|
+
id: msg.id,
|
|
100
|
+
subject: msg.subject,
|
|
101
|
+
from: msg.from?.emailAddress?.address,
|
|
102
|
+
fromName: msg.from?.emailAddress?.name,
|
|
103
|
+
to: msg.toRecipients?.map((r: any) => ({ email: r.emailAddress?.address, name: r.emailAddress?.name })),
|
|
104
|
+
cc: msg.ccRecipients?.map((r: any) => ({ email: r.emailAddress?.address, name: r.emailAddress?.name })),
|
|
105
|
+
bcc: msg.bccRecipients?.map((r: any) => ({ email: r.emailAddress?.address, name: r.emailAddress?.name })),
|
|
106
|
+
replyTo: msg.replyTo?.map((r: any) => r.emailAddress?.address),
|
|
107
|
+
date: msg.receivedDateTime,
|
|
108
|
+
sentDate: msg.sentDateTime,
|
|
109
|
+
body: msg.body?.content,
|
|
110
|
+
bodyType: msg.body?.contentType,
|
|
111
|
+
isRead: msg.isRead,
|
|
112
|
+
importance: msg.importance,
|
|
113
|
+
attachments,
|
|
114
|
+
conversationId: msg.conversationId,
|
|
115
|
+
internetMessageId: msg.internetMessageId,
|
|
116
|
+
});
|
|
117
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
name: 'outlook_mail_send',
|
|
123
|
+
description: 'Send an email via Outlook. Supports to, cc, bcc, HTML body, importance, and reply-to.',
|
|
124
|
+
category: 'utility' as const,
|
|
125
|
+
parameters: {
|
|
126
|
+
type: 'object' as const,
|
|
127
|
+
properties: {
|
|
128
|
+
to: { type: 'string', description: 'Recipient email(s), comma-separated' },
|
|
129
|
+
subject: { type: 'string', description: 'Email subject' },
|
|
130
|
+
body: { type: 'string', description: 'Email body (HTML or plain text)' },
|
|
131
|
+
cc: { type: 'string', description: 'CC recipients, comma-separated' },
|
|
132
|
+
bcc: { type: 'string', description: 'BCC recipients, comma-separated' },
|
|
133
|
+
importance: { type: 'string', description: 'low, normal, or high (default: normal)' },
|
|
134
|
+
isHtml: { type: 'boolean', description: 'Whether body is HTML (default: false)' },
|
|
135
|
+
replyTo: { type: 'string', description: 'Reply-to address' },
|
|
136
|
+
saveToSent: { type: 'boolean', description: 'Save to Sent Items (default: true)' },
|
|
137
|
+
},
|
|
138
|
+
required: ['to', 'subject', 'body'],
|
|
139
|
+
},
|
|
140
|
+
async execute(_id: string, params: any) {
|
|
141
|
+
try {
|
|
142
|
+
const token = await tp.getAccessToken();
|
|
143
|
+
const toRecipients = params.to.split(',').map((e: string) => ({
|
|
144
|
+
emailAddress: { address: e.trim() }
|
|
145
|
+
}));
|
|
146
|
+
const message: any = {
|
|
147
|
+
subject: params.subject,
|
|
148
|
+
body: { contentType: params.isHtml ? 'HTML' : 'Text', content: params.body },
|
|
149
|
+
toRecipients,
|
|
150
|
+
};
|
|
151
|
+
if (params.cc) message.ccRecipients = params.cc.split(',').map((e: string) => ({ emailAddress: { address: e.trim() } }));
|
|
152
|
+
if (params.bcc) message.bccRecipients = params.bcc.split(',').map((e: string) => ({ emailAddress: { address: e.trim() } }));
|
|
153
|
+
if (params.importance) message.importance = params.importance;
|
|
154
|
+
if (params.replyTo) message.replyTo = [{ emailAddress: { address: params.replyTo } }];
|
|
155
|
+
|
|
156
|
+
await graph(token, '/me/sendMail', {
|
|
157
|
+
method: 'POST',
|
|
158
|
+
body: { message, saveToSentItems: params.saveToSent !== false },
|
|
159
|
+
});
|
|
160
|
+
return jsonResult({ sent: true, to: params.to, subject: params.subject });
|
|
161
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
{
|
|
166
|
+
name: 'outlook_mail_reply',
|
|
167
|
+
description: 'Reply to an email message. Can reply to sender only or reply-all.',
|
|
168
|
+
category: 'utility' as const,
|
|
169
|
+
parameters: {
|
|
170
|
+
type: 'object' as const,
|
|
171
|
+
properties: {
|
|
172
|
+
messageId: { type: 'string', description: 'Message ID to reply to' },
|
|
173
|
+
body: { type: 'string', description: 'Reply body text' },
|
|
174
|
+
replyAll: { type: 'boolean', description: 'Reply to all recipients (default: false)' },
|
|
175
|
+
isHtml: { type: 'boolean', description: 'Whether body is HTML (default: false)' },
|
|
176
|
+
},
|
|
177
|
+
required: ['messageId', 'body'],
|
|
178
|
+
},
|
|
179
|
+
async execute(_id: string, params: any) {
|
|
180
|
+
try {
|
|
181
|
+
const token = await tp.getAccessToken();
|
|
182
|
+
const action = params.replyAll ? 'replyAll' : 'reply';
|
|
183
|
+
await graph(token, `/me/messages/${params.messageId}/${action}`, {
|
|
184
|
+
method: 'POST',
|
|
185
|
+
body: { comment: params.body },
|
|
186
|
+
});
|
|
187
|
+
return jsonResult({ replied: true, messageId: params.messageId, replyAll: !!params.replyAll });
|
|
188
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
{
|
|
193
|
+
name: 'outlook_mail_forward',
|
|
194
|
+
description: 'Forward an email message to another recipient.',
|
|
195
|
+
category: 'utility' as const,
|
|
196
|
+
parameters: {
|
|
197
|
+
type: 'object' as const,
|
|
198
|
+
properties: {
|
|
199
|
+
messageId: { type: 'string', description: 'Message ID to forward' },
|
|
200
|
+
to: { type: 'string', description: 'Forward recipient email(s), comma-separated' },
|
|
201
|
+
comment: { type: 'string', description: 'Optional comment to add above the forwarded message' },
|
|
202
|
+
},
|
|
203
|
+
required: ['messageId', 'to'],
|
|
204
|
+
},
|
|
205
|
+
async execute(_id: string, params: any) {
|
|
206
|
+
try {
|
|
207
|
+
const token = await tp.getAccessToken();
|
|
208
|
+
const toRecipients = params.to.split(',').map((e: string) => ({ emailAddress: { address: e.trim() } }));
|
|
209
|
+
await graph(token, `/me/messages/${params.messageId}/forward`, {
|
|
210
|
+
method: 'POST',
|
|
211
|
+
body: { comment: params.comment || '', toRecipients },
|
|
212
|
+
});
|
|
213
|
+
return jsonResult({ forwarded: true, messageId: params.messageId, to: params.to });
|
|
214
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
{
|
|
219
|
+
name: 'outlook_mail_move',
|
|
220
|
+
description: 'Move a message to another folder.',
|
|
221
|
+
category: 'utility' as const,
|
|
222
|
+
parameters: {
|
|
223
|
+
type: 'object' as const,
|
|
224
|
+
properties: {
|
|
225
|
+
messageId: { type: 'string', description: 'Message ID to move' },
|
|
226
|
+
folder: { type: 'string', description: 'Destination folder: inbox, archive, deleteditems, junkemail, or folder ID' },
|
|
227
|
+
},
|
|
228
|
+
required: ['messageId', 'folder'],
|
|
229
|
+
},
|
|
230
|
+
async execute(_id: string, params: any) {
|
|
231
|
+
try {
|
|
232
|
+
const token = await tp.getAccessToken();
|
|
233
|
+
// Resolve well-known folder names
|
|
234
|
+
const folderMap: Record<string, string> = {
|
|
235
|
+
inbox: 'inbox', archive: 'archive', trash: 'deleteditems',
|
|
236
|
+
deleteditems: 'deleteditems', junk: 'junkemail', junkemail: 'junkemail',
|
|
237
|
+
sent: 'sentitems', sentitems: 'sentitems', drafts: 'drafts',
|
|
238
|
+
};
|
|
239
|
+
const destId = folderMap[params.folder.toLowerCase()] || params.folder;
|
|
240
|
+
const result = await graph(token, `/me/messages/${params.messageId}/move`, {
|
|
241
|
+
method: 'POST',
|
|
242
|
+
body: { destinationId: destId },
|
|
243
|
+
});
|
|
244
|
+
return jsonResult({ moved: true, newId: result.id, folder: params.folder });
|
|
245
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
{
|
|
250
|
+
name: 'outlook_mail_delete',
|
|
251
|
+
description: 'Delete an email message (moves to Deleted Items).',
|
|
252
|
+
category: 'utility' as const,
|
|
253
|
+
parameters: {
|
|
254
|
+
type: 'object' as const,
|
|
255
|
+
properties: {
|
|
256
|
+
messageId: { type: 'string', description: 'Message ID to delete' },
|
|
257
|
+
},
|
|
258
|
+
required: ['messageId'],
|
|
259
|
+
},
|
|
260
|
+
async execute(_id: string, params: any) {
|
|
261
|
+
try {
|
|
262
|
+
const token = await tp.getAccessToken();
|
|
263
|
+
await graph(token, `/me/messages/${params.messageId}`, { method: 'DELETE' });
|
|
264
|
+
return jsonResult({ deleted: true, messageId: params.messageId });
|
|
265
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
{
|
|
270
|
+
name: 'outlook_mail_update',
|
|
271
|
+
description: 'Update message properties: mark as read/unread, flag, change importance, add categories.',
|
|
272
|
+
category: 'utility' as const,
|
|
273
|
+
parameters: {
|
|
274
|
+
type: 'object' as const,
|
|
275
|
+
properties: {
|
|
276
|
+
messageId: { type: 'string', description: 'Message ID to update' },
|
|
277
|
+
isRead: { type: 'boolean', description: 'Mark as read or unread' },
|
|
278
|
+
importance: { type: 'string', description: 'low, normal, or high' },
|
|
279
|
+
flag: { type: 'string', description: 'notFlagged, flagged, or complete' },
|
|
280
|
+
categories: { type: 'array', items: { type: 'string' }, description: 'Category labels to apply' },
|
|
281
|
+
},
|
|
282
|
+
required: ['messageId'],
|
|
283
|
+
},
|
|
284
|
+
async execute(_id: string, params: any) {
|
|
285
|
+
try {
|
|
286
|
+
const token = await tp.getAccessToken();
|
|
287
|
+
const body: any = {};
|
|
288
|
+
if (params.isRead !== undefined) body.isRead = params.isRead;
|
|
289
|
+
if (params.importance) body.importance = params.importance;
|
|
290
|
+
if (params.flag) body.flag = { flagStatus: params.flag };
|
|
291
|
+
if (params.categories) body.categories = params.categories;
|
|
292
|
+
await graph(token, `/me/messages/${params.messageId}`, { method: 'PATCH', body });
|
|
293
|
+
return jsonResult({ updated: true, messageId: params.messageId });
|
|
294
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
{
|
|
299
|
+
name: 'outlook_mail_search',
|
|
300
|
+
description: 'Search emails across all folders using Microsoft Search. Supports natural language queries.',
|
|
301
|
+
category: 'utility' as const,
|
|
302
|
+
parameters: {
|
|
303
|
+
type: 'object' as const,
|
|
304
|
+
properties: {
|
|
305
|
+
query: { type: 'string', description: 'Search query (natural language or KQL: "from:user@example.com subject:report")' },
|
|
306
|
+
maxResults: { type: 'number', description: 'Max results (default: 10, max: 25)' },
|
|
307
|
+
},
|
|
308
|
+
required: ['query'],
|
|
309
|
+
},
|
|
310
|
+
async execute(_id: string, params: any) {
|
|
311
|
+
try {
|
|
312
|
+
const token = await tp.getAccessToken();
|
|
313
|
+
const top = Math.min(params.maxResults || 10, 25);
|
|
314
|
+
// Use $search on messages endpoint
|
|
315
|
+
const data = await graph(token, '/me/messages', {
|
|
316
|
+
query: {
|
|
317
|
+
'$search': `"${params.query}"`,
|
|
318
|
+
'$top': String(top),
|
|
319
|
+
'$select': 'id,subject,from,receivedDateTime,bodyPreview,isRead,hasAttachments,importance',
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
const messages = (data.value || []).map((m: any) => ({
|
|
323
|
+
id: m.id,
|
|
324
|
+
subject: m.subject,
|
|
325
|
+
from: m.from?.emailAddress?.address,
|
|
326
|
+
fromName: m.from?.emailAddress?.name,
|
|
327
|
+
date: m.receivedDateTime,
|
|
328
|
+
preview: m.bodyPreview,
|
|
329
|
+
isRead: m.isRead,
|
|
330
|
+
hasAttachments: m.hasAttachments,
|
|
331
|
+
}));
|
|
332
|
+
return jsonResult({ messages, count: messages.length, query: params.query });
|
|
333
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
{
|
|
338
|
+
name: 'outlook_mail_draft',
|
|
339
|
+
description: 'Create a draft email in Outlook. Can be edited and sent later.',
|
|
340
|
+
category: 'utility' as const,
|
|
341
|
+
parameters: {
|
|
342
|
+
type: 'object' as const,
|
|
343
|
+
properties: {
|
|
344
|
+
to: { type: 'string', description: 'Recipient email(s), comma-separated' },
|
|
345
|
+
subject: { type: 'string', description: 'Email subject' },
|
|
346
|
+
body: { type: 'string', description: 'Email body' },
|
|
347
|
+
cc: { type: 'string', description: 'CC recipients' },
|
|
348
|
+
isHtml: { type: 'boolean', description: 'Whether body is HTML' },
|
|
349
|
+
},
|
|
350
|
+
required: ['to', 'subject', 'body'],
|
|
351
|
+
},
|
|
352
|
+
async execute(_id: string, params: any) {
|
|
353
|
+
try {
|
|
354
|
+
const token = await tp.getAccessToken();
|
|
355
|
+
const message: any = {
|
|
356
|
+
subject: params.subject,
|
|
357
|
+
body: { contentType: params.isHtml ? 'HTML' : 'Text', content: params.body },
|
|
358
|
+
toRecipients: params.to.split(',').map((e: string) => ({ emailAddress: { address: e.trim() } })),
|
|
359
|
+
};
|
|
360
|
+
if (params.cc) message.ccRecipients = params.cc.split(',').map((e: string) => ({ emailAddress: { address: e.trim() } }));
|
|
361
|
+
const draft = await graph(token, '/me/messages', { method: 'POST', body: message });
|
|
362
|
+
return jsonResult({ draftId: draft.id, subject: params.subject, status: 'draft_created' });
|
|
363
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
{
|
|
368
|
+
name: 'outlook_mail_send_draft',
|
|
369
|
+
description: 'Send an existing draft email.',
|
|
370
|
+
category: 'utility' as const,
|
|
371
|
+
parameters: {
|
|
372
|
+
type: 'object' as const,
|
|
373
|
+
properties: {
|
|
374
|
+
messageId: { type: 'string', description: 'Draft message ID to send' },
|
|
375
|
+
},
|
|
376
|
+
required: ['messageId'],
|
|
377
|
+
},
|
|
378
|
+
async execute(_id: string, params: any) {
|
|
379
|
+
try {
|
|
380
|
+
const token = await tp.getAccessToken();
|
|
381
|
+
await graph(token, `/me/messages/${params.messageId}/send`, { method: 'POST' });
|
|
382
|
+
return jsonResult({ sent: true, messageId: params.messageId });
|
|
383
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
{
|
|
388
|
+
name: 'outlook_mail_folders',
|
|
389
|
+
description: 'List mail folders in the mailbox.',
|
|
390
|
+
category: 'utility' as const,
|
|
391
|
+
parameters: { type: 'object' as const, properties: {}, required: [] },
|
|
392
|
+
async execute(_id: string) {
|
|
393
|
+
try {
|
|
394
|
+
const token = await tp.getAccessToken();
|
|
395
|
+
const data = await graph(token, '/me/mailFolders', {
|
|
396
|
+
query: { '$top': '50', '$select': 'id,displayName,totalItemCount,unreadItemCount,parentFolderId' }
|
|
397
|
+
});
|
|
398
|
+
const folders = (data.value || []).map((f: any) => ({
|
|
399
|
+
id: f.id, name: f.displayName,
|
|
400
|
+
totalItems: f.totalItemCount, unreadItems: f.unreadItemCount,
|
|
401
|
+
}));
|
|
402
|
+
return jsonResult({ folders, count: folders.length });
|
|
403
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
{
|
|
408
|
+
name: 'outlook_mail_attachment_download',
|
|
409
|
+
description: 'Download an attachment from an email. Returns the attachment content as base64.',
|
|
410
|
+
category: 'utility' as const,
|
|
411
|
+
parameters: {
|
|
412
|
+
type: 'object' as const,
|
|
413
|
+
properties: {
|
|
414
|
+
messageId: { type: 'string', description: 'Message ID containing the attachment' },
|
|
415
|
+
attachmentId: { type: 'string', description: 'Attachment ID to download' },
|
|
416
|
+
},
|
|
417
|
+
required: ['messageId', 'attachmentId'],
|
|
418
|
+
},
|
|
419
|
+
async execute(_id: string, params: any) {
|
|
420
|
+
try {
|
|
421
|
+
const token = await tp.getAccessToken();
|
|
422
|
+
const att = await graph(token, `/me/messages/${params.messageId}/attachments/${params.attachmentId}`);
|
|
423
|
+
return jsonResult({
|
|
424
|
+
name: att.name, contentType: att.contentType, size: att.size,
|
|
425
|
+
content: att.contentBytes, // base64 encoded
|
|
426
|
+
});
|
|
427
|
+
} catch (e: any) { return errorResult(e.message); }
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
];
|
|
431
|
+
}
|