@marlinjai/email-mcp 1.10.1 → 1.11.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 +6 -0
- package/dist/index.js +185 -34
- package/dist/index.js.map +4 -4
- package/dist/setup/wizard.js +60 -3
- package/dist/setup/wizard.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -143,6 +143,12 @@ npx -y -p @marlinjai/email-mcp@latest email-mcp-setup
|
|
|
143
143
|
|
|
144
144
|
`email_send`, `email_reply`, `email_forward`, `email_draft_create` and `email_draft_update` take an optional `attachments` list. Each entry is either `{ path }` (a file in the attachments folder, see below) or `{ content, filename }` (base64), with an optional `contentType` (inferred from the extension otherwise). The total is capped at 25 MB; Outlook accepts up to 3 MB per message through this server. On `email_draft_update` a list replaces the draft's files, an empty list removes them, and no list keeps the files the draft has.
|
|
145
145
|
|
|
146
|
+
**Gmail adds your signature, like Gmail's own editor.** The Gmail API never appends one, so `email_send`, `email_reply`, `email_forward`, `email_draft_create` and `email_draft_update` read the signature of the send-as address the mail goes out from (Gmail settings, read on every call, so a changed signature applies at once) and add it in Gmail's own markup (`gmail_signature`), above any quoted history, plus a plain-text rendering in the text part. A text-only body gains an HTML part for it, as the signature's logo and links only exist as HTML. A body that already holds a signature (a `gmail_signature` block, or a `-- ` line in text) is left alone, so passing a draft's body back to `email_draft_update` never stacks a second one. `signature: false` turns it off for one call. Each of these tools returns a `signature` field saying what happened: `added`, `already_present`, `disabled`, `none_configured`, `unsupported`, or `skipped` with the reason (for example a missing permission); a failed read never blocks the mail or draft.
|
|
147
|
+
|
|
148
|
+
**Outlook, iCloud and IMAP add no signature.** Microsoft Graph has no signature API for Outlook.com accounts (signatures live in the Outlook clients, out of reach for a server), and an IMAP or iCloud server keeps no signature at all. The tools report `unsupported` there instead of inventing one; put the signature in the body when the mail needs it. A signature stored in email-mcp's own account settings was considered and left out on purpose: it would be a second copy that drifts from the one in the mail client, which is exactly how old mail ends up with an outdated signature.
|
|
149
|
+
|
|
150
|
+
**From names you.** The From header carries a display name, not just the address: on Gmail the send-as display name from Gmail's settings, otherwise the account's name in email-mcp (unless that is only a label: a provider name such as "Gmail" or "iCloud", or the address's local part such as "founder"). Gmail often keeps no display name for an account's primary address (its web editor then uses the Google profile name, which this server cannot read); set one under Settings, Accounts, "Send mail as", edit info, and the tools use it. This also holds for a draft sent later from another mail program, which keeps the draft's From. Outlook sets From itself.
|
|
151
|
+
|
|
146
152
|
Replies stay in their thread: `email_reply` sends inside the original conversation on Gmail and Outlook (and sets the `In-Reply-To` and `References` headers everywhere), `email_draft_create` with `inReplyToEmailId` saves a reply draft in that thread, and `email_draft_update` keeps a reply draft there.
|
|
147
153
|
|
|
148
154
|
**Forwarding the original message's attachments is opt-in.** `email_forward` sends the text of the original; its files go along only with `includeOriginalAttachments: true`, so one call does not pass files the assistant never looked at on to another address. Forwarded files count against the 25 MB cap together with added ones.
|
package/dist/index.js
CHANGED
|
@@ -7181,6 +7181,16 @@ function normalizeBody(body) {
|
|
|
7181
7181
|
function toAddress(contact) {
|
|
7182
7182
|
return contact.name ? { name: contact.name, address: contact.email } : contact.email;
|
|
7183
7183
|
}
|
|
7184
|
+
function fromAddress(email3, displayName, accountName) {
|
|
7185
|
+
const own = displayName?.trim();
|
|
7186
|
+
if (own) return { name: own, address: email3 };
|
|
7187
|
+
const fallback = accountName?.trim();
|
|
7188
|
+
const label = (name) => PROVIDER_LABELS.has(name) || name === email3.toLowerCase() || name === email3.toLowerCase().split("@")[0];
|
|
7189
|
+
if (fallback && !label(fallback.toLowerCase())) {
|
|
7190
|
+
return { name: fallback, address: email3 };
|
|
7191
|
+
}
|
|
7192
|
+
return email3;
|
|
7193
|
+
}
|
|
7184
7194
|
function toAddressList(contacts) {
|
|
7185
7195
|
return contacts?.length ? contacts.map(toAddress) : void 0;
|
|
7186
7196
|
}
|
|
@@ -7206,9 +7216,11 @@ async function buildMimeMessage(from, params) {
|
|
|
7206
7216
|
node.keepBcc = true;
|
|
7207
7217
|
return node.build();
|
|
7208
7218
|
}
|
|
7219
|
+
var PROVIDER_LABELS;
|
|
7209
7220
|
var init_mime = __esm({
|
|
7210
7221
|
"src/providers/mime.ts"() {
|
|
7211
7222
|
"use strict";
|
|
7223
|
+
PROVIDER_LABELS = /* @__PURE__ */ new Set(["gmail", "outlook", "icloud", "imap"]);
|
|
7212
7224
|
}
|
|
7213
7225
|
});
|
|
7214
7226
|
|
|
@@ -7228,12 +7240,14 @@ var init_adapter = __esm({
|
|
|
7228
7240
|
gmail = null;
|
|
7229
7241
|
accountId = "";
|
|
7230
7242
|
email = "";
|
|
7243
|
+
accountName = "";
|
|
7231
7244
|
async connect(credentials) {
|
|
7232
7245
|
if (!credentials.oauth) {
|
|
7233
7246
|
throw new Error("Gmail adapter requires OAuth credentials");
|
|
7234
7247
|
}
|
|
7235
7248
|
this.accountId = credentials.id;
|
|
7236
7249
|
this.email = credentials.email;
|
|
7250
|
+
this.accountName = credentials.name;
|
|
7237
7251
|
const auth = new OAuth2Client();
|
|
7238
7252
|
auth.setCredentials({
|
|
7239
7253
|
access_token: credentials.oauth.access_token,
|
|
@@ -7431,6 +7445,43 @@ var init_adapter = __esm({
|
|
|
7431
7445
|
});
|
|
7432
7446
|
return { id: res.data.id || draftId };
|
|
7433
7447
|
}
|
|
7448
|
+
/**
|
|
7449
|
+
* The signature Gmail's own editor would add: the one of the send-as
|
|
7450
|
+
* address the From header names (`this.email`, see buildRaw), or the
|
|
7451
|
+
* default send-as when that address is not listed. Read on every call, so
|
|
7452
|
+
* a signature changed in Gmail's settings applies to the next mail.
|
|
7453
|
+
*/
|
|
7454
|
+
async getSignature() {
|
|
7455
|
+
const entries = await this.sendAsList();
|
|
7456
|
+
const entry = this.ownSendAs(entries) || entries.find((e) => e.isDefault);
|
|
7457
|
+
if (!entry) throw new Error(`Gmail lists no send-as address for ${this.email}`);
|
|
7458
|
+
const html = (entry.signature || "").trim();
|
|
7459
|
+
return { sendAs: entry.sendAsEmail || this.email, html: html || null };
|
|
7460
|
+
}
|
|
7461
|
+
async sendAsList() {
|
|
7462
|
+
const gmail = this.ensureConnected();
|
|
7463
|
+
const res = await gmail.users.settings.sendAs.list({ userId: "me" });
|
|
7464
|
+
return res.data.sendAs || [];
|
|
7465
|
+
}
|
|
7466
|
+
ownSendAs(entries) {
|
|
7467
|
+
const own = this.email.toLowerCase();
|
|
7468
|
+
return entries.find((e) => (e.sendAsEmail || "").toLowerCase() === own);
|
|
7469
|
+
}
|
|
7470
|
+
/**
|
|
7471
|
+
* The From header: the account's address with the display name Gmail
|
|
7472
|
+
* keeps for it as a send-as address. When the settings cannot be read the
|
|
7473
|
+
* mail still goes out, named after the account (see `fromAddress`); the
|
|
7474
|
+
* signature outcome in the tool result already reports that failure.
|
|
7475
|
+
*/
|
|
7476
|
+
async from() {
|
|
7477
|
+
let displayName;
|
|
7478
|
+
try {
|
|
7479
|
+
displayName = this.ownSendAs(await this.sendAsList())?.displayName || void 0;
|
|
7480
|
+
} catch {
|
|
7481
|
+
displayName = void 0;
|
|
7482
|
+
}
|
|
7483
|
+
return fromAddress(this.email, displayName, this.accountName);
|
|
7484
|
+
}
|
|
7434
7485
|
async listDrafts(limit, _offset) {
|
|
7435
7486
|
const gmail = this.ensureConnected();
|
|
7436
7487
|
const res = await gmail.users.drafts.list({
|
|
@@ -7857,7 +7908,7 @@ var init_adapter = __esm({
|
|
|
7857
7908
|
* and any attachments. See `buildMimeMessage`.
|
|
7858
7909
|
*/
|
|
7859
7910
|
async buildRaw(params) {
|
|
7860
|
-
const message = await buildMimeMessage(this.
|
|
7911
|
+
const message = await buildMimeMessage(await this.from(), params);
|
|
7861
7912
|
return message.toString("base64url");
|
|
7862
7913
|
}
|
|
7863
7914
|
};
|
|
@@ -9128,6 +9179,7 @@ var init_adapter3 = __esm({
|
|
|
9128
9179
|
client = null;
|
|
9129
9180
|
accountId = "";
|
|
9130
9181
|
email = "";
|
|
9182
|
+
accountName = "";
|
|
9131
9183
|
passwordCreds = null;
|
|
9132
9184
|
connectingPromise = null;
|
|
9133
9185
|
async connect(credentials) {
|
|
@@ -9136,6 +9188,7 @@ var init_adapter3 = __esm({
|
|
|
9136
9188
|
}
|
|
9137
9189
|
this.accountId = credentials.id;
|
|
9138
9190
|
this.email = credentials.email;
|
|
9191
|
+
this.accountName = credentials.name;
|
|
9139
9192
|
this.passwordCreds = credentials.password;
|
|
9140
9193
|
await this.ensureConnected();
|
|
9141
9194
|
}
|
|
@@ -9568,7 +9621,7 @@ var init_adapter3 = __esm({
|
|
|
9568
9621
|
async sendEmail(params) {
|
|
9569
9622
|
if (!this.passwordCreds) throw new Error("No credentials available");
|
|
9570
9623
|
const transport = createSmtpTransport(this.email, this.passwordCreds);
|
|
9571
|
-
const messageId = await sendViaSmtp(transport, this.
|
|
9624
|
+
const messageId = await sendViaSmtp(transport, this.from(), params);
|
|
9572
9625
|
return { id: messageId };
|
|
9573
9626
|
}
|
|
9574
9627
|
/**
|
|
@@ -9577,7 +9630,12 @@ var init_adapter3 = __esm({
|
|
|
9577
9630
|
* attachments. See `buildMimeMessage`.
|
|
9578
9631
|
*/
|
|
9579
9632
|
buildDraftMessage(params) {
|
|
9580
|
-
return buildMimeMessage(this.
|
|
9633
|
+
return buildMimeMessage(this.from(), params);
|
|
9634
|
+
}
|
|
9635
|
+
/** IMAP keeps no display name on the server, so the account's name is the
|
|
9636
|
+
* only one there is (see `fromAddress`). */
|
|
9637
|
+
from() {
|
|
9638
|
+
return fromAddress(this.email, void 0, this.accountName);
|
|
9581
9639
|
}
|
|
9582
9640
|
async createDraft(params) {
|
|
9583
9641
|
const client = await this.ensureConnected();
|
|
@@ -34312,6 +34370,78 @@ function assertAttachmentTotal(totalBytes) {
|
|
|
34312
34370
|
}
|
|
34313
34371
|
}
|
|
34314
34372
|
|
|
34373
|
+
// src/tools/signature.ts
|
|
34374
|
+
init_mime();
|
|
34375
|
+
function escapeHtml(text) {
|
|
34376
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
34377
|
+
}
|
|
34378
|
+
function textToHtml(text) {
|
|
34379
|
+
return `<div dir="ltr">${escapeHtml(text).replace(/\r?\n/g, "<br>")}</div>`;
|
|
34380
|
+
}
|
|
34381
|
+
var TEXT_DELIMITER = /^-- \r?$/m;
|
|
34382
|
+
var HTML_QUOTE = /<(?:div|blockquote)\b[^>]*\bclass="[^"]*\bgmail_quote/i;
|
|
34383
|
+
var TEXT_QUOTE = /^(?:-{10} Forwarded message -{10}|On .+ wrote:)\s*$/m;
|
|
34384
|
+
function hasSignature(body) {
|
|
34385
|
+
return /\bgmail_signature\b/.test(body.html ?? "") || TEXT_DELIMITER.test(body.text ?? "");
|
|
34386
|
+
}
|
|
34387
|
+
function renderSignature(signatureHtml) {
|
|
34388
|
+
return {
|
|
34389
|
+
html: `<span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">${signatureHtml}</div>`,
|
|
34390
|
+
text: `--
|
|
34391
|
+
${htmlToText(signatureHtml)}`
|
|
34392
|
+
};
|
|
34393
|
+
}
|
|
34394
|
+
function insertBefore(content, quote, block, separator) {
|
|
34395
|
+
const match = quote.exec(content);
|
|
34396
|
+
const at = match ? match.index : content.length;
|
|
34397
|
+
const before = content.slice(0, at).replace(/\s+$/, "");
|
|
34398
|
+
const after = content.slice(at);
|
|
34399
|
+
return [before, block, after].filter(Boolean).join(separator);
|
|
34400
|
+
}
|
|
34401
|
+
function withSignature(body, signatureHtml) {
|
|
34402
|
+
const signature = renderSignature(signatureHtml);
|
|
34403
|
+
const html = body.html ?? (body.text ? textToHtml(body.text) : "");
|
|
34404
|
+
const text = body.text ?? (body.html ? htmlToText(body.html) : "");
|
|
34405
|
+
return {
|
|
34406
|
+
html: insertBefore(html, HTML_QUOTE, `<div>${signature.html}</div>`, "<br>"),
|
|
34407
|
+
text: insertBefore(text, TEXT_QUOTE, signature.text, "\n\n")
|
|
34408
|
+
};
|
|
34409
|
+
}
|
|
34410
|
+
function unsupportedReason(provider) {
|
|
34411
|
+
if (provider === "outlook") {
|
|
34412
|
+
return "Outlook: Microsoft Graph has no signature API for Outlook.com accounts, so no signature was added. Put it in the body if the mail needs one.";
|
|
34413
|
+
}
|
|
34414
|
+
return `${provider === "icloud" ? "iCloud" : "IMAP"}: the server keeps no signature a client can read, so no signature was added. Put it in the body if the mail needs one.`;
|
|
34415
|
+
}
|
|
34416
|
+
async function resolveSignature(provider, body, enabled) {
|
|
34417
|
+
if (enabled === false) return { body, signature: { status: "disabled" } };
|
|
34418
|
+
if (hasSignature(body)) return { body, signature: { status: "already_present" } };
|
|
34419
|
+
if (!provider.getSignature) {
|
|
34420
|
+
return { body, signature: { status: "unsupported", reason: unsupportedReason(provider.providerType) } };
|
|
34421
|
+
}
|
|
34422
|
+
let found;
|
|
34423
|
+
try {
|
|
34424
|
+
found = await provider.getSignature();
|
|
34425
|
+
} catch (error48) {
|
|
34426
|
+
const message = error48?.message || String(error48);
|
|
34427
|
+
return {
|
|
34428
|
+
body,
|
|
34429
|
+
signature: { status: "skipped", reason: `The signature could not be read, so none was added: ${message}` }
|
|
34430
|
+
};
|
|
34431
|
+
}
|
|
34432
|
+
if (!found.html) {
|
|
34433
|
+
return {
|
|
34434
|
+
body,
|
|
34435
|
+
signature: {
|
|
34436
|
+
status: "none_configured",
|
|
34437
|
+
sendAs: found.sendAs,
|
|
34438
|
+
reason: `${found.sendAs} has no signature in Gmail's settings.`
|
|
34439
|
+
}
|
|
34440
|
+
};
|
|
34441
|
+
}
|
|
34442
|
+
return { body: withSignature(body, found.html), signature: { status: "added", sendAs: found.sendAs } };
|
|
34443
|
+
}
|
|
34444
|
+
|
|
34315
34445
|
// src/tools/sending.ts
|
|
34316
34446
|
var ContactSchema = external_exports3.object({
|
|
34317
34447
|
email: external_exports3.string(),
|
|
@@ -34321,6 +34451,9 @@ var BodySchema = external_exports3.object({
|
|
|
34321
34451
|
text: external_exports3.string().optional(),
|
|
34322
34452
|
html: external_exports3.string().optional()
|
|
34323
34453
|
});
|
|
34454
|
+
var SignatureSchema = external_exports3.boolean().optional().describe(
|
|
34455
|
+
"Add the account's signature (default true). Gmail: the signature of the send-as address the mail goes out from, read from Gmail's settings, in Gmail's own markup above any quoted history; a body that already holds one is left alone. Outlook.com, iCloud and IMAP have no signature a client can read, so nothing is added there. The result's `signature` field says what happened"
|
|
34456
|
+
);
|
|
34324
34457
|
function jsonResult3(data) {
|
|
34325
34458
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
34326
34459
|
}
|
|
@@ -34360,21 +34493,24 @@ function registerSendingTools(server, accountManager) {
|
|
|
34360
34493
|
bcc: external_exports3.array(ContactSchema).optional(),
|
|
34361
34494
|
subject: external_exports3.string(),
|
|
34362
34495
|
body: BodySchema,
|
|
34363
|
-
attachments: AttachmentsSchema
|
|
34496
|
+
attachments: AttachmentsSchema,
|
|
34497
|
+
signature: SignatureSchema
|
|
34364
34498
|
},
|
|
34365
34499
|
async (args) => {
|
|
34366
34500
|
try {
|
|
34367
34501
|
const provider = await accountManager.getProvider(args.accountId);
|
|
34502
|
+
const attachments = resolveAttachments(args.attachments);
|
|
34503
|
+
const { body, signature } = await resolveSignature(provider, args.body, args.signature);
|
|
34368
34504
|
const params = {
|
|
34369
34505
|
to: args.to,
|
|
34370
34506
|
cc: args.cc,
|
|
34371
34507
|
bcc: args.bcc,
|
|
34372
34508
|
subject: args.subject,
|
|
34373
|
-
body
|
|
34374
|
-
attachments
|
|
34509
|
+
body,
|
|
34510
|
+
attachments
|
|
34375
34511
|
};
|
|
34376
34512
|
const result = await provider.sendEmail(params);
|
|
34377
|
-
return jsonResult3(result);
|
|
34513
|
+
return jsonResult3({ ...result, signature });
|
|
34378
34514
|
} catch (error48) {
|
|
34379
34515
|
return jsonResult3({ error: error48.message });
|
|
34380
34516
|
}
|
|
@@ -34393,7 +34529,8 @@ function registerSendingTools(server, accountManager) {
|
|
|
34393
34529
|
cc: external_exports3.array(ContactSchema).optional().describe("Cc recipients. Replaces any Cc carried over by replyAll"),
|
|
34394
34530
|
bcc: external_exports3.array(ContactSchema).optional(),
|
|
34395
34531
|
additionalRecipients: external_exports3.array(ContactSchema).optional().describe("Extra To recipients added to the default or given To (deduplicated by address)"),
|
|
34396
|
-
attachments: AttachmentsSchema
|
|
34532
|
+
attachments: AttachmentsSchema,
|
|
34533
|
+
signature: SignatureSchema
|
|
34397
34534
|
},
|
|
34398
34535
|
async (args) => {
|
|
34399
34536
|
try {
|
|
@@ -34421,17 +34558,19 @@ function registerSendingTools(server, accountManager) {
|
|
|
34421
34558
|
}
|
|
34422
34559
|
if (args.cc !== void 0) cc = args.cc;
|
|
34423
34560
|
if (args.replyAll) ({ to, cc } = withoutDuplicates(to, cc));
|
|
34561
|
+
const attachments = resolveAttachments(args.attachments);
|
|
34562
|
+
const { body, signature } = await resolveSignature(provider, args.body, args.signature);
|
|
34424
34563
|
const params = {
|
|
34425
34564
|
to,
|
|
34426
34565
|
cc,
|
|
34427
34566
|
bcc: args.bcc,
|
|
34428
34567
|
subject,
|
|
34429
|
-
body
|
|
34568
|
+
body,
|
|
34430
34569
|
...replyThreading(original),
|
|
34431
|
-
attachments
|
|
34570
|
+
attachments
|
|
34432
34571
|
};
|
|
34433
34572
|
const result = await provider.sendEmail(params);
|
|
34434
|
-
return jsonResult3(result);
|
|
34573
|
+
return jsonResult3({ ...result, signature });
|
|
34435
34574
|
} catch (error48) {
|
|
34436
34575
|
return jsonResult3({ error: error48.message });
|
|
34437
34576
|
}
|
|
@@ -34449,12 +34588,14 @@ function registerSendingTools(server, accountManager) {
|
|
|
34449
34588
|
body: BodySchema.optional(),
|
|
34450
34589
|
attachments: AttachmentsSchema.describe("Files to attach to the forward. Total size, together with forwarded original attachments, is capped at 25 MB"),
|
|
34451
34590
|
includeOriginalAttachments: external_exports3.boolean().optional().describe("Also forward the original message's attachments (default false). Leave it off unless the user asked for the files to go along"),
|
|
34452
|
-
sourceFolder: external_exports3.string().optional().describe("Source folder (required for IMAP/iCloud when email is not in INBOX)")
|
|
34591
|
+
sourceFolder: external_exports3.string().optional().describe("Source folder (required for IMAP/iCloud when email is not in INBOX)"),
|
|
34592
|
+
signature: SignatureSchema
|
|
34453
34593
|
},
|
|
34454
34594
|
async (args) => {
|
|
34455
34595
|
try {
|
|
34456
34596
|
const provider = await accountManager.getProvider(args.accountId);
|
|
34457
34597
|
const original = await provider.getEmail(args.emailId, args.sourceFolder);
|
|
34598
|
+
const { body: note, signature } = await resolveSignature(provider, args.body ?? {}, args.signature);
|
|
34458
34599
|
const subject = original.subject.startsWith("Fwd: ") ? original.subject : `Fwd: ${original.subject}`;
|
|
34459
34600
|
const forwardHeader = [
|
|
34460
34601
|
"---------- Forwarded message ----------",
|
|
@@ -34464,7 +34605,7 @@ function registerSendingTools(server, accountManager) {
|
|
|
34464
34605
|
`To: ${original.to.map((c) => c.name ? `${c.name} <${c.email}>` : c.email).join(", ")}`,
|
|
34465
34606
|
""
|
|
34466
34607
|
].join("\n");
|
|
34467
|
-
const additionalText =
|
|
34608
|
+
const additionalText = note.text ?? "";
|
|
34468
34609
|
const originalText = original.body.text ?? "";
|
|
34469
34610
|
const forwardedText = [
|
|
34470
34611
|
additionalText,
|
|
@@ -34473,19 +34614,22 @@ function registerSendingTools(server, accountManager) {
|
|
|
34473
34614
|
originalText
|
|
34474
34615
|
].join("");
|
|
34475
34616
|
let forwardedHtml;
|
|
34476
|
-
if (original.body.html ||
|
|
34477
|
-
const additionalHtml =
|
|
34478
|
-
const originalHtml = original.body.html ?? "";
|
|
34617
|
+
if (original.body.html || note.html) {
|
|
34618
|
+
const additionalHtml = note.html ?? "";
|
|
34619
|
+
const originalHtml = original.body.html ?? textToHtml(original.body.text ?? "");
|
|
34620
|
+
const contact = (c) => escapeHtml(c.name ? `${c.name} <${c.email}>` : c.email);
|
|
34479
34621
|
forwardedHtml = [
|
|
34480
34622
|
additionalHtml,
|
|
34481
34623
|
"<br/><hr/>",
|
|
34624
|
+
'<div class="gmail_quote">',
|
|
34482
34625
|
`<b>---------- Forwarded message ----------</b><br/>`,
|
|
34483
|
-
`From: ${original.from
|
|
34484
|
-
`Date: ${original.date}<br/>`,
|
|
34485
|
-
`Subject: ${original.subject}<br/>`,
|
|
34486
|
-
`To: ${original.to.map(
|
|
34626
|
+
`From: ${contact(original.from)}<br/>`,
|
|
34627
|
+
`Date: ${escapeHtml(original.date)}<br/>`,
|
|
34628
|
+
`Subject: ${escapeHtml(original.subject)}<br/>`,
|
|
34629
|
+
`To: ${original.to.map(contact).join(", ")}<br/>`,
|
|
34487
34630
|
"<br/>",
|
|
34488
|
-
originalHtml
|
|
34631
|
+
originalHtml,
|
|
34632
|
+
"</div>"
|
|
34489
34633
|
].join("");
|
|
34490
34634
|
}
|
|
34491
34635
|
const extra = resolveAttachments(args.attachments) ?? [];
|
|
@@ -34511,7 +34655,7 @@ function registerSendingTools(server, accountManager) {
|
|
|
34511
34655
|
attachments: attachments.length ? attachments : void 0
|
|
34512
34656
|
};
|
|
34513
34657
|
const result = await provider.sendEmail(params);
|
|
34514
|
-
return jsonResult3(result);
|
|
34658
|
+
return jsonResult3({ ...result, signature });
|
|
34515
34659
|
} catch (error48) {
|
|
34516
34660
|
return jsonResult3({ error: error48.message });
|
|
34517
34661
|
}
|
|
@@ -34527,22 +34671,24 @@ function registerSendingTools(server, accountManager) {
|
|
|
34527
34671
|
body: BodySchema,
|
|
34528
34672
|
attachments: AttachmentsSchema,
|
|
34529
34673
|
inReplyToEmailId: external_exports3.string().optional().describe("Id of the email this draft replies to. The draft joins that thread (Gmail threadId, Outlook createReply, In-Reply-To/References headers elsewhere)"),
|
|
34530
|
-
inReplyToSourceFolder: external_exports3.string().optional().describe("Folder of the email named in inReplyToEmailId (required for IMAP/iCloud when that email is not in INBOX). The draft itself is saved to Drafts")
|
|
34674
|
+
inReplyToSourceFolder: external_exports3.string().optional().describe("Folder of the email named in inReplyToEmailId (required for IMAP/iCloud when that email is not in INBOX). The draft itself is saved to Drafts"),
|
|
34675
|
+
signature: SignatureSchema
|
|
34531
34676
|
},
|
|
34532
34677
|
async (args) => {
|
|
34533
34678
|
try {
|
|
34534
34679
|
const provider = await accountManager.getProvider(args.accountId);
|
|
34680
|
+
const attachments = resolveAttachments(args.attachments);
|
|
34681
|
+
const threading = args.inReplyToEmailId ? replyThreading(await provider.getEmail(args.inReplyToEmailId, args.inReplyToSourceFolder)) : {};
|
|
34682
|
+
const { body, signature } = await resolveSignature(provider, args.body, args.signature);
|
|
34535
34683
|
const params = {
|
|
34536
34684
|
to: args.to,
|
|
34537
34685
|
subject: args.subject,
|
|
34538
|
-
body
|
|
34539
|
-
attachments
|
|
34686
|
+
body,
|
|
34687
|
+
attachments,
|
|
34688
|
+
...threading
|
|
34540
34689
|
};
|
|
34541
|
-
if (args.inReplyToEmailId) {
|
|
34542
|
-
Object.assign(params, replyThreading(await provider.getEmail(args.inReplyToEmailId, args.inReplyToSourceFolder)));
|
|
34543
|
-
}
|
|
34544
34690
|
const result = await provider.createDraft(params);
|
|
34545
|
-
return jsonResult3(result);
|
|
34691
|
+
return jsonResult3({ ...result, signature });
|
|
34546
34692
|
} catch (error48) {
|
|
34547
34693
|
return jsonResult3({ error: error48.message });
|
|
34548
34694
|
}
|
|
@@ -34560,19 +34706,24 @@ function registerSendingTools(server, accountManager) {
|
|
|
34560
34706
|
attachments: AttachmentsSchema.describe(
|
|
34561
34707
|
"Files to attach. When given, they replace the draft's current attachments; an empty list removes them all. When omitted, the draft keeps the files it has."
|
|
34562
34708
|
),
|
|
34563
|
-
sourceFolder: external_exports3.string().optional().describe("Source folder (required for IMAP/iCloud when the draft is not in the default Drafts folder)")
|
|
34709
|
+
sourceFolder: external_exports3.string().optional().describe("Source folder (required for IMAP/iCloud when the draft is not in the default Drafts folder)"),
|
|
34710
|
+
signature: SignatureSchema.describe(
|
|
34711
|
+
"Add the account's signature (default true), as on email_draft_create. The body given here replaces the draft's body, so the signature is added to it once; a body that already holds one (passed back from the draft) is left alone, so repeated updates never stack a second one"
|
|
34712
|
+
)
|
|
34564
34713
|
},
|
|
34565
34714
|
async (args) => {
|
|
34566
34715
|
try {
|
|
34567
34716
|
const provider = await accountManager.getProvider(args.accountId);
|
|
34717
|
+
const attachments = resolveAttachments(args.attachments);
|
|
34718
|
+
const { body, signature } = await resolveSignature(provider, args.body, args.signature);
|
|
34568
34719
|
const params = {
|
|
34569
34720
|
to: args.to,
|
|
34570
34721
|
subject: args.subject,
|
|
34571
|
-
body
|
|
34572
|
-
attachments
|
|
34722
|
+
body,
|
|
34723
|
+
attachments
|
|
34573
34724
|
};
|
|
34574
34725
|
const result = await provider.updateDraft(args.draftId, params, args.sourceFolder);
|
|
34575
|
-
return jsonResult3(result);
|
|
34726
|
+
return jsonResult3({ ...result, signature });
|
|
34576
34727
|
} catch (error48) {
|
|
34577
34728
|
return jsonResult3({ error: error48.message });
|
|
34578
34729
|
}
|
|
@@ -35222,7 +35373,7 @@ function registerForwardingTools(server, accountManager) {
|
|
|
35222
35373
|
}
|
|
35223
35374
|
|
|
35224
35375
|
// src/server.ts
|
|
35225
|
-
var SERVER_VERSION = "1.
|
|
35376
|
+
var SERVER_VERSION = "1.11.0";
|
|
35226
35377
|
async function createServer(accountManager) {
|
|
35227
35378
|
const mgr = accountManager ?? new AccountManager();
|
|
35228
35379
|
const server = new McpServer({
|