fastmail-cli 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.
- package/README.md +127 -0
- package/index.ts +58 -0
- package/openclaw.plugin.json +31 -0
- package/package.json +38 -0
- package/skills/fastmail/SKILL.md +136 -0
- package/src/auth.ts +27 -0
- package/src/formatters.ts +321 -0
- package/src/mcp-client.ts +150 -0
- package/src/tools/calendar.ts +77 -0
- package/src/tools/contacts.ts +55 -0
- package/src/tools/email.ts +493 -0
- package/src/tools/memo.ts +56 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email tools for the Fastmail OpenClaw plugin.
|
|
3
|
+
*
|
|
4
|
+
* 11 read + 3 write + 6 organize + 6 bulk = 26 tools total.
|
|
5
|
+
* Write/organize/bulk tools use { optional: true }.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { OpenClawApi, GetClientFn } from "../../index.js";
|
|
9
|
+
import {
|
|
10
|
+
formatEmailList,
|
|
11
|
+
formatEmail,
|
|
12
|
+
formatMailboxes,
|
|
13
|
+
formatMailboxStats,
|
|
14
|
+
formatAccountSummary,
|
|
15
|
+
formatIdentities,
|
|
16
|
+
formatAttachments,
|
|
17
|
+
formatInboxUpdates,
|
|
18
|
+
} from "../formatters.js";
|
|
19
|
+
|
|
20
|
+
export function registerEmailTools(api: OpenClawApi, getClient: GetClientFn) {
|
|
21
|
+
// -- Read (11 tools) ------------------------------------------------
|
|
22
|
+
|
|
23
|
+
api.registerTool({
|
|
24
|
+
name: "fastmail_inbox",
|
|
25
|
+
description: "Get recent inbox emails with IDs, dates, senders, subjects, and previews.",
|
|
26
|
+
parameters: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
limit: { type: "integer", default: 10, description: "Number of emails" },
|
|
30
|
+
mailboxName: { type: "string", default: "inbox", description: "Mailbox name" },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
async execute(_id: string, params: { limit?: number; mailboxName?: string }) {
|
|
34
|
+
const client = await getClient();
|
|
35
|
+
const data = await client.callTool("get_recent_emails", {
|
|
36
|
+
limit: params.limit ?? 10,
|
|
37
|
+
mailboxName: params.mailboxName ?? "inbox",
|
|
38
|
+
});
|
|
39
|
+
const text = Array.isArray(data) ? formatEmailList(data, params.mailboxName ?? "inbox") : String(data);
|
|
40
|
+
return { content: [{ type: "text", text }] };
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
api.registerTool({
|
|
45
|
+
name: "fastmail_get_email",
|
|
46
|
+
description: "Read a single email by ID. Returns formatted headers + body.",
|
|
47
|
+
parameters: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
emailId: { type: "string", description: "Email ID" },
|
|
51
|
+
format: { type: "string", enum: ["markdown", "html"], default: "markdown", description: "Body format" },
|
|
52
|
+
},
|
|
53
|
+
required: ["emailId"],
|
|
54
|
+
},
|
|
55
|
+
async execute(_id: string, params: { emailId: string; format?: string }) {
|
|
56
|
+
const client = await getClient();
|
|
57
|
+
const data = await client.callTool("get_email", {
|
|
58
|
+
emailId: params.emailId,
|
|
59
|
+
format: params.format ?? "markdown",
|
|
60
|
+
});
|
|
61
|
+
return { content: [{ type: "text", text: formatEmail(data) }] };
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
api.registerTool({
|
|
66
|
+
name: "fastmail_search_emails",
|
|
67
|
+
description: "Search emails with text and optional filters: sender, recipient, date range, unread, attachments, mailbox.",
|
|
68
|
+
parameters: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: {
|
|
71
|
+
query: { type: "string", description: "Search query text" },
|
|
72
|
+
limit: { type: "integer", default: 20, description: "Max results" },
|
|
73
|
+
from: { type: "string", description: "Filter by sender" },
|
|
74
|
+
to: { type: "string", description: "Filter by recipient" },
|
|
75
|
+
subject: { type: "string", description: "Filter by subject" },
|
|
76
|
+
after: { type: "string", description: "After date (ISO 8601)" },
|
|
77
|
+
before: { type: "string", description: "Before date (ISO 8601)" },
|
|
78
|
+
isUnread: { type: "boolean", description: "Only unread" },
|
|
79
|
+
hasAttachment: { type: "boolean", description: "Only with attachments" },
|
|
80
|
+
mailboxId: { type: "string", description: "Restrict to mailbox" },
|
|
81
|
+
},
|
|
82
|
+
required: ["query"],
|
|
83
|
+
},
|
|
84
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
85
|
+
const client = await getClient();
|
|
86
|
+
const hasFilters = params.from || params.to || params.subject || params.after || params.before || params.isUnread || params.hasAttachment || params.mailboxId;
|
|
87
|
+
const tool = hasFilters ? "advanced_search" : "search_emails";
|
|
88
|
+
const data = await client.callTool(tool, {
|
|
89
|
+
query: params.query,
|
|
90
|
+
limit: params.limit ?? 20,
|
|
91
|
+
...(hasFilters && {
|
|
92
|
+
from: params.from, to: params.to, subject: params.subject,
|
|
93
|
+
after: params.after, before: params.before,
|
|
94
|
+
isUnread: params.isUnread, hasAttachment: params.hasAttachment,
|
|
95
|
+
mailboxId: params.mailboxId,
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
const text = Array.isArray(data) ? formatEmailList(data, `Search: ${params.query}`) : String(data);
|
|
99
|
+
return { content: [{ type: "text", text }] };
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
api.registerTool({
|
|
104
|
+
name: "fastmail_get_thread",
|
|
105
|
+
description: "Get all emails in a conversation thread.",
|
|
106
|
+
parameters: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
threadId: { type: "string", description: "Thread ID" },
|
|
110
|
+
format: { type: "string", enum: ["markdown", "html"], default: "markdown" },
|
|
111
|
+
},
|
|
112
|
+
required: ["threadId"],
|
|
113
|
+
},
|
|
114
|
+
async execute(_id: string, params: { threadId: string; format?: string }) {
|
|
115
|
+
const client = await getClient();
|
|
116
|
+
const data = await client.callTool("get_thread", { threadId: params.threadId, format: params.format ?? "markdown" });
|
|
117
|
+
let text: string;
|
|
118
|
+
if (typeof data === "string") text = data;
|
|
119
|
+
else if (Array.isArray(data)) text = data.map(formatEmail).join("\n\n---\n\n");
|
|
120
|
+
else text = JSON.stringify(data, null, 2);
|
|
121
|
+
return { content: [{ type: "text", text }] };
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
api.registerTool({
|
|
126
|
+
name: "fastmail_list_mailboxes",
|
|
127
|
+
description: "List all mailboxes with IDs, names, roles, and email counts.",
|
|
128
|
+
parameters: { type: "object", properties: {} },
|
|
129
|
+
async execute(_id: string, _params: Record<string, never>) {
|
|
130
|
+
const client = await getClient();
|
|
131
|
+
return { content: [{ type: "text", text: formatMailboxes(await client.callTool("list_mailboxes")) }] };
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
api.registerTool({
|
|
136
|
+
name: "fastmail_get_mailbox_stats",
|
|
137
|
+
description: "Get statistics for a specific mailbox or all mailboxes.",
|
|
138
|
+
parameters: {
|
|
139
|
+
type: "object",
|
|
140
|
+
properties: { mailboxId: { type: "string", description: "Mailbox ID (omit for all)" } },
|
|
141
|
+
},
|
|
142
|
+
async execute(_id: string, params: { mailboxId?: string }) {
|
|
143
|
+
const client = await getClient();
|
|
144
|
+
const args: Record<string, unknown> = {};
|
|
145
|
+
if (params.mailboxId) args.mailboxId = params.mailboxId;
|
|
146
|
+
return { content: [{ type: "text", text: formatMailboxStats(await client.callTool("get_mailbox_stats", args)) }] };
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
api.registerTool({
|
|
151
|
+
name: "fastmail_get_account_summary",
|
|
152
|
+
description: "Get account overview: mailbox count, identity count, total/unread emails.",
|
|
153
|
+
parameters: { type: "object", properties: {} },
|
|
154
|
+
async execute(_id: string, _params: Record<string, never>) {
|
|
155
|
+
const client = await getClient();
|
|
156
|
+
return { content: [{ type: "text", text: formatAccountSummary(await client.callTool("get_account_summary")) }] };
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
api.registerTool({
|
|
161
|
+
name: "fastmail_list_identities",
|
|
162
|
+
description: "List sending identities (email addresses and names).",
|
|
163
|
+
parameters: { type: "object", properties: {} },
|
|
164
|
+
async execute(_id: string, _params: Record<string, never>) {
|
|
165
|
+
const client = await getClient();
|
|
166
|
+
return { content: [{ type: "text", text: formatIdentities(await client.callTool("list_identities")) }] };
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
api.registerTool({
|
|
171
|
+
name: "fastmail_get_attachments",
|
|
172
|
+
description: "List attachments for an email.",
|
|
173
|
+
parameters: {
|
|
174
|
+
type: "object",
|
|
175
|
+
properties: { emailId: { type: "string", description: "Email ID" } },
|
|
176
|
+
required: ["emailId"],
|
|
177
|
+
},
|
|
178
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
179
|
+
const client = await getClient();
|
|
180
|
+
const data = await client.callTool("get_email_attachments", { emailId: params.emailId });
|
|
181
|
+
return { content: [{ type: "text", text: Array.isArray(data) ? formatAttachments(data) : String(data) }] };
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
api.registerTool({
|
|
186
|
+
name: "fastmail_download_attachment",
|
|
187
|
+
description: "Get download URL or inline content for an attachment.",
|
|
188
|
+
parameters: {
|
|
189
|
+
type: "object",
|
|
190
|
+
properties: {
|
|
191
|
+
emailId: { type: "string", description: "Email ID" },
|
|
192
|
+
attachmentId: { type: "string", description: "Attachment blob ID" },
|
|
193
|
+
inline: { type: "boolean", default: false, description: "Return base64 inline" },
|
|
194
|
+
},
|
|
195
|
+
required: ["emailId", "attachmentId"],
|
|
196
|
+
},
|
|
197
|
+
async execute(_id: string, params: { emailId: string; attachmentId: string; inline?: boolean }) {
|
|
198
|
+
const client = await getClient();
|
|
199
|
+
const data = await client.callTool("download_attachment", {
|
|
200
|
+
emailId: params.emailId, attachmentId: params.attachmentId, inline: params.inline ?? false,
|
|
201
|
+
});
|
|
202
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data, null, 2) }] };
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
api.registerTool({
|
|
207
|
+
name: "fastmail_get_inbox_updates",
|
|
208
|
+
description: "Get inbox changes since a state token (incremental sync).",
|
|
209
|
+
parameters: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: {
|
|
212
|
+
sinceQueryState: { type: "string", description: "State token from previous call" },
|
|
213
|
+
mailboxId: { type: "string", description: "Mailbox ID" },
|
|
214
|
+
limit: { type: "integer", default: 100, description: "Max results" },
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
async execute(_id: string, params: { sinceQueryState?: string; mailboxId?: string; limit?: number }) {
|
|
218
|
+
const client = await getClient();
|
|
219
|
+
const data = await client.callTool("get_inbox_updates", {
|
|
220
|
+
sinceQueryState: params.sinceQueryState, mailboxId: params.mailboxId, limit: params.limit ?? 100,
|
|
221
|
+
});
|
|
222
|
+
return { content: [{ type: "text", text: typeof data === "object" && data !== null ? formatInboxUpdates(data) : String(data) }] };
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// -- Write (3 tools, optional) --------------------------------------
|
|
227
|
+
|
|
228
|
+
api.registerTool({
|
|
229
|
+
name: "fastmail_send_email",
|
|
230
|
+
description: "Send an email. Supports plain text, HTML, or markdown body.",
|
|
231
|
+
parameters: {
|
|
232
|
+
type: "object",
|
|
233
|
+
properties: {
|
|
234
|
+
to: { type: "array", items: { type: "string" }, description: "Recipients" },
|
|
235
|
+
subject: { type: "string", description: "Subject" },
|
|
236
|
+
textBody: { type: "string", description: "Plain text body" },
|
|
237
|
+
htmlBody: { type: "string", description: "HTML body" },
|
|
238
|
+
markdownBody: { type: "string", description: "Markdown body" },
|
|
239
|
+
cc: { type: "array", items: { type: "string" }, description: "CC" },
|
|
240
|
+
bcc: { type: "array", items: { type: "string" }, description: "BCC" },
|
|
241
|
+
from: { type: "string", description: "Sender address" },
|
|
242
|
+
},
|
|
243
|
+
required: ["to", "subject"],
|
|
244
|
+
},
|
|
245
|
+
async execute(_id: string, params: { to: string[]; subject: string; textBody?: string; htmlBody?: string; markdownBody?: string; cc?: string[]; bcc?: string[]; from?: string }) {
|
|
246
|
+
const client = await getClient();
|
|
247
|
+
const data = await client.callTool("send_email", {
|
|
248
|
+
to: params.to, subject: params.subject,
|
|
249
|
+
...(params.textBody && { textBody: params.textBody }),
|
|
250
|
+
...(params.htmlBody && { htmlBody: params.htmlBody }),
|
|
251
|
+
...(params.markdownBody && { markdownBody: params.markdownBody }),
|
|
252
|
+
...(params.cc && { cc: params.cc }),
|
|
253
|
+
...(params.bcc && { bcc: params.bcc }),
|
|
254
|
+
...(params.from && { from: params.from }),
|
|
255
|
+
});
|
|
256
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data) }] };
|
|
257
|
+
},
|
|
258
|
+
}, { optional: true });
|
|
259
|
+
|
|
260
|
+
api.registerTool({
|
|
261
|
+
name: "fastmail_create_draft",
|
|
262
|
+
description: "Create an email draft.",
|
|
263
|
+
parameters: {
|
|
264
|
+
type: "object",
|
|
265
|
+
properties: {
|
|
266
|
+
to: { type: "array", items: { type: "string" }, description: "Recipients" },
|
|
267
|
+
subject: { type: "string", description: "Subject" },
|
|
268
|
+
textBody: { type: "string", description: "Plain text body" },
|
|
269
|
+
htmlBody: { type: "string", description: "HTML body" },
|
|
270
|
+
markdownBody: { type: "string", description: "Markdown body" },
|
|
271
|
+
cc: { type: "array", items: { type: "string" }, description: "CC" },
|
|
272
|
+
bcc: { type: "array", items: { type: "string" }, description: "BCC" },
|
|
273
|
+
from: { type: "string", description: "Sender address" },
|
|
274
|
+
},
|
|
275
|
+
required: ["to", "subject"],
|
|
276
|
+
},
|
|
277
|
+
async execute(_id: string, params: { to: string[]; subject: string; textBody?: string; htmlBody?: string; markdownBody?: string; cc?: string[]; bcc?: string[]; from?: string }) {
|
|
278
|
+
const client = await getClient();
|
|
279
|
+
const data = await client.callTool("create_draft", {
|
|
280
|
+
to: params.to, subject: params.subject,
|
|
281
|
+
...(params.textBody && { textBody: params.textBody }),
|
|
282
|
+
...(params.htmlBody && { htmlBody: params.htmlBody }),
|
|
283
|
+
...(params.markdownBody && { markdownBody: params.markdownBody }),
|
|
284
|
+
...(params.cc && { cc: params.cc }),
|
|
285
|
+
...(params.bcc && { bcc: params.bcc }),
|
|
286
|
+
...(params.from && { from: params.from }),
|
|
287
|
+
});
|
|
288
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data) }] };
|
|
289
|
+
},
|
|
290
|
+
}, { optional: true });
|
|
291
|
+
|
|
292
|
+
api.registerTool({
|
|
293
|
+
name: "fastmail_reply_to_email",
|
|
294
|
+
description: "Reply to an email. Can reply-all, send immediately or save as draft.",
|
|
295
|
+
parameters: {
|
|
296
|
+
type: "object",
|
|
297
|
+
properties: {
|
|
298
|
+
emailId: { type: "string", description: "Email ID to reply to" },
|
|
299
|
+
body: { type: "string", description: "Reply text" },
|
|
300
|
+
htmlBody: { type: "string", description: "HTML reply body" },
|
|
301
|
+
markdownBody: { type: "string", description: "Markdown reply body" },
|
|
302
|
+
from: { type: "string", description: "Sender address" },
|
|
303
|
+
replyAll: { type: "boolean", default: false, description: "Reply to all" },
|
|
304
|
+
sendImmediately: { type: "boolean", default: false, description: "Send now vs draft" },
|
|
305
|
+
excludeQuote: { type: "boolean", default: false, description: "Exclude quoted original" },
|
|
306
|
+
},
|
|
307
|
+
required: ["emailId", "body"],
|
|
308
|
+
},
|
|
309
|
+
async execute(_id: string, params: { emailId: string; body: string; htmlBody?: string; markdownBody?: string; from?: string; replyAll?: boolean; sendImmediately?: boolean; excludeQuote?: boolean }) {
|
|
310
|
+
const client = await getClient();
|
|
311
|
+
const data = await client.callTool("reply_to_email", {
|
|
312
|
+
emailId: params.emailId, body: params.body,
|
|
313
|
+
...(params.htmlBody && { htmlBody: params.htmlBody }),
|
|
314
|
+
...(params.markdownBody && { markdownBody: params.markdownBody }),
|
|
315
|
+
...(params.from && { from: params.from }),
|
|
316
|
+
...(params.replyAll !== undefined && { replyAll: params.replyAll }),
|
|
317
|
+
...(params.sendImmediately !== undefined && { sendImmediately: params.sendImmediately }),
|
|
318
|
+
...(params.excludeQuote !== undefined && { excludeQuote: params.excludeQuote }),
|
|
319
|
+
});
|
|
320
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data) }] };
|
|
321
|
+
},
|
|
322
|
+
}, { optional: true });
|
|
323
|
+
|
|
324
|
+
// -- Organize (6 tools, optional) -----------------------------------
|
|
325
|
+
|
|
326
|
+
api.registerTool({
|
|
327
|
+
name: "fastmail_mark_read",
|
|
328
|
+
description: "Mark an email as read.",
|
|
329
|
+
parameters: { type: "object", properties: { emailId: { type: "string" } }, required: ["emailId"] },
|
|
330
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
331
|
+
const client = await getClient();
|
|
332
|
+
const data = await client.callTool("mark_email_read", { emailId: params.emailId, read: true });
|
|
333
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : "Marked as read" }] };
|
|
334
|
+
},
|
|
335
|
+
}, { optional: true });
|
|
336
|
+
|
|
337
|
+
api.registerTool({
|
|
338
|
+
name: "fastmail_mark_unread",
|
|
339
|
+
description: "Mark an email as unread.",
|
|
340
|
+
parameters: { type: "object", properties: { emailId: { type: "string" } }, required: ["emailId"] },
|
|
341
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
342
|
+
const client = await getClient();
|
|
343
|
+
const data = await client.callTool("mark_email_read", { emailId: params.emailId, read: false });
|
|
344
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : "Marked as unread" }] };
|
|
345
|
+
},
|
|
346
|
+
}, { optional: true });
|
|
347
|
+
|
|
348
|
+
api.registerTool({
|
|
349
|
+
name: "fastmail_flag",
|
|
350
|
+
description: "Flag (star) an email.",
|
|
351
|
+
parameters: { type: "object", properties: { emailId: { type: "string" } }, required: ["emailId"] },
|
|
352
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
353
|
+
const client = await getClient();
|
|
354
|
+
const data = await client.callTool("flag_email", { emailId: params.emailId, flagged: true });
|
|
355
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : "Flagged" }] };
|
|
356
|
+
},
|
|
357
|
+
}, { optional: true });
|
|
358
|
+
|
|
359
|
+
api.registerTool({
|
|
360
|
+
name: "fastmail_unflag",
|
|
361
|
+
description: "Unflag (unstar) an email.",
|
|
362
|
+
parameters: { type: "object", properties: { emailId: { type: "string" } }, required: ["emailId"] },
|
|
363
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
364
|
+
const client = await getClient();
|
|
365
|
+
const data = await client.callTool("flag_email", { emailId: params.emailId, flagged: false });
|
|
366
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : "Unflagged" }] };
|
|
367
|
+
},
|
|
368
|
+
}, { optional: true });
|
|
369
|
+
|
|
370
|
+
api.registerTool({
|
|
371
|
+
name: "fastmail_delete",
|
|
372
|
+
description: "Delete an email (move to trash).",
|
|
373
|
+
parameters: { type: "object", properties: { emailId: { type: "string" } }, required: ["emailId"] },
|
|
374
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
375
|
+
const client = await getClient();
|
|
376
|
+
const data = await client.callTool("delete_email", { emailId: params.emailId });
|
|
377
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : "Deleted" }] };
|
|
378
|
+
},
|
|
379
|
+
}, { optional: true });
|
|
380
|
+
|
|
381
|
+
api.registerTool({
|
|
382
|
+
name: "fastmail_move",
|
|
383
|
+
description: "Move an email to a different mailbox.",
|
|
384
|
+
parameters: {
|
|
385
|
+
type: "object",
|
|
386
|
+
properties: {
|
|
387
|
+
emailId: { type: "string", description: "Email ID" },
|
|
388
|
+
targetMailboxId: { type: "string", description: "Target mailbox ID" },
|
|
389
|
+
},
|
|
390
|
+
required: ["emailId", "targetMailboxId"],
|
|
391
|
+
},
|
|
392
|
+
async execute(_id: string, params: { emailId: string; targetMailboxId: string }) {
|
|
393
|
+
const client = await getClient();
|
|
394
|
+
const data = await client.callTool("move_email", { emailId: params.emailId, targetMailboxId: params.targetMailboxId });
|
|
395
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : "Moved" }] };
|
|
396
|
+
},
|
|
397
|
+
}, { optional: true });
|
|
398
|
+
|
|
399
|
+
// -- Bulk (6 tools, optional) ---------------------------------------
|
|
400
|
+
|
|
401
|
+
api.registerTool({
|
|
402
|
+
name: "fastmail_bulk_read",
|
|
403
|
+
description: "Mark multiple emails as read.",
|
|
404
|
+
parameters: {
|
|
405
|
+
type: "object",
|
|
406
|
+
properties: { emailIds: { type: "array", items: { type: "string" } } },
|
|
407
|
+
required: ["emailIds"],
|
|
408
|
+
},
|
|
409
|
+
async execute(_id: string, params: { emailIds: string[] }) {
|
|
410
|
+
const client = await getClient();
|
|
411
|
+
const data = await client.callTool("bulk_mark_read", { emailIds: params.emailIds, read: true });
|
|
412
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : `${params.emailIds.length} marked read` }] };
|
|
413
|
+
},
|
|
414
|
+
}, { optional: true });
|
|
415
|
+
|
|
416
|
+
api.registerTool({
|
|
417
|
+
name: "fastmail_bulk_unread",
|
|
418
|
+
description: "Mark multiple emails as unread.",
|
|
419
|
+
parameters: {
|
|
420
|
+
type: "object",
|
|
421
|
+
properties: { emailIds: { type: "array", items: { type: "string" } } },
|
|
422
|
+
required: ["emailIds"],
|
|
423
|
+
},
|
|
424
|
+
async execute(_id: string, params: { emailIds: string[] }) {
|
|
425
|
+
const client = await getClient();
|
|
426
|
+
const data = await client.callTool("bulk_mark_read", { emailIds: params.emailIds, read: false });
|
|
427
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : `${params.emailIds.length} marked unread` }] };
|
|
428
|
+
},
|
|
429
|
+
}, { optional: true });
|
|
430
|
+
|
|
431
|
+
api.registerTool({
|
|
432
|
+
name: "fastmail_bulk_flag",
|
|
433
|
+
description: "Flag multiple emails.",
|
|
434
|
+
parameters: {
|
|
435
|
+
type: "object",
|
|
436
|
+
properties: { emailIds: { type: "array", items: { type: "string" } } },
|
|
437
|
+
required: ["emailIds"],
|
|
438
|
+
},
|
|
439
|
+
async execute(_id: string, params: { emailIds: string[] }) {
|
|
440
|
+
const client = await getClient();
|
|
441
|
+
const data = await client.callTool("bulk_flag", { emailIds: params.emailIds, flagged: true });
|
|
442
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : `${params.emailIds.length} flagged` }] };
|
|
443
|
+
},
|
|
444
|
+
}, { optional: true });
|
|
445
|
+
|
|
446
|
+
api.registerTool({
|
|
447
|
+
name: "fastmail_bulk_unflag",
|
|
448
|
+
description: "Unflag multiple emails.",
|
|
449
|
+
parameters: {
|
|
450
|
+
type: "object",
|
|
451
|
+
properties: { emailIds: { type: "array", items: { type: "string" } } },
|
|
452
|
+
required: ["emailIds"],
|
|
453
|
+
},
|
|
454
|
+
async execute(_id: string, params: { emailIds: string[] }) {
|
|
455
|
+
const client = await getClient();
|
|
456
|
+
const data = await client.callTool("bulk_flag", { emailIds: params.emailIds, flagged: false });
|
|
457
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : `${params.emailIds.length} unflagged` }] };
|
|
458
|
+
},
|
|
459
|
+
}, { optional: true });
|
|
460
|
+
|
|
461
|
+
api.registerTool({
|
|
462
|
+
name: "fastmail_bulk_delete",
|
|
463
|
+
description: "Delete multiple emails.",
|
|
464
|
+
parameters: {
|
|
465
|
+
type: "object",
|
|
466
|
+
properties: { emailIds: { type: "array", items: { type: "string" } } },
|
|
467
|
+
required: ["emailIds"],
|
|
468
|
+
},
|
|
469
|
+
async execute(_id: string, params: { emailIds: string[] }) {
|
|
470
|
+
const client = await getClient();
|
|
471
|
+
const data = await client.callTool("bulk_delete", { emailIds: params.emailIds });
|
|
472
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : `${params.emailIds.length} deleted` }] };
|
|
473
|
+
},
|
|
474
|
+
}, { optional: true });
|
|
475
|
+
|
|
476
|
+
api.registerTool({
|
|
477
|
+
name: "fastmail_bulk_move",
|
|
478
|
+
description: "Move multiple emails to a mailbox.",
|
|
479
|
+
parameters: {
|
|
480
|
+
type: "object",
|
|
481
|
+
properties: {
|
|
482
|
+
emailIds: { type: "array", items: { type: "string" } },
|
|
483
|
+
targetMailboxId: { type: "string", description: "Target mailbox ID" },
|
|
484
|
+
},
|
|
485
|
+
required: ["emailIds", "targetMailboxId"],
|
|
486
|
+
},
|
|
487
|
+
async execute(_id: string, params: { emailIds: string[]; targetMailboxId: string }) {
|
|
488
|
+
const client = await getClient();
|
|
489
|
+
const data = await client.callTool("bulk_move", { emailIds: params.emailIds, targetMailboxId: params.targetMailboxId });
|
|
490
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : `${params.emailIds.length} moved` }] };
|
|
491
|
+
},
|
|
492
|
+
}, { optional: true });
|
|
493
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memo (private notes) tools for the Fastmail OpenClaw plugin.
|
|
3
|
+
* 1 read-only + 2 optional (create, delete).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { OpenClawApi, GetClientFn } from "../../index.js";
|
|
7
|
+
import { formatMemo } from "../formatters.js";
|
|
8
|
+
|
|
9
|
+
export function registerMemoTools(api: OpenClawApi, getClient: GetClientFn) {
|
|
10
|
+
api.registerTool({
|
|
11
|
+
name: "fastmail_get_memo",
|
|
12
|
+
description: "Get the private memo on an email, if one exists.",
|
|
13
|
+
parameters: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: { emailId: { type: "string", description: "Email ID" } },
|
|
16
|
+
required: ["emailId"],
|
|
17
|
+
},
|
|
18
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
19
|
+
const client = await getClient();
|
|
20
|
+
return { content: [{ type: "text", text: formatMemo(await client.callTool("get_memo", { emailId: params.emailId })) }] };
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
api.registerTool({
|
|
25
|
+
name: "fastmail_create_memo",
|
|
26
|
+
description: "Add a private memo to an email. Shown as a yellow highlight in Fastmail.",
|
|
27
|
+
parameters: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
emailId: { type: "string", description: "Email ID" },
|
|
31
|
+
text: { type: "string", description: "Memo text" },
|
|
32
|
+
},
|
|
33
|
+
required: ["emailId", "text"],
|
|
34
|
+
},
|
|
35
|
+
async execute(_id: string, params: { emailId: string; text: string }) {
|
|
36
|
+
const client = await getClient();
|
|
37
|
+
const data = await client.callTool("create_memo", params);
|
|
38
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data) }] };
|
|
39
|
+
},
|
|
40
|
+
}, { optional: true });
|
|
41
|
+
|
|
42
|
+
api.registerTool({
|
|
43
|
+
name: "fastmail_delete_memo",
|
|
44
|
+
description: "Delete the private memo on an email.",
|
|
45
|
+
parameters: {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: { emailId: { type: "string", description: "Email ID" } },
|
|
48
|
+
required: ["emailId"],
|
|
49
|
+
},
|
|
50
|
+
async execute(_id: string, params: { emailId: string }) {
|
|
51
|
+
const client = await getClient();
|
|
52
|
+
const data = await client.callTool("delete_memo", { emailId: params.emailId });
|
|
53
|
+
return { content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data) }] };
|
|
54
|
+
},
|
|
55
|
+
}, { optional: true });
|
|
56
|
+
}
|