Add optional mailbox (UPN/SMTP) routing on email/folder/thread tools via
users/{upn}/... and X-AnchorMailbox. New list-mailboxes probes primary,
OUTLOOK_SHARED_MAILBOXES seeds, cache, and candidates. Send supports
mailbox-rooted sendMail and onBehalfOf. MSAL requests Mail.*.Shared;
check-auth-status reports token scp gaps. Docs, env example, tests.
202 lines
7.1 KiB
JavaScript
202 lines
7.1 KiB
JavaScript
/**
|
|
* Email module for Outlook MCP server
|
|
*/
|
|
const handleListEmails = require('./list');
|
|
const handleSearchEmails = require('./search');
|
|
const handleReadEmail = require('./read');
|
|
const handleReadMultipleEmails = require('./read-multiple');
|
|
const handleSendEmail = require('./send');
|
|
|
|
const mailboxProp = {
|
|
type: "string",
|
|
description: "Optional shared/delegated mailbox UPN or SMTP (e.g. 'helpdesk@contoso.com'). Omit for the signed-in user's primary mailbox. Message IDs are mailbox-scoped — pass the same mailbox on read/thread calls."
|
|
};
|
|
|
|
// Email tool definitions
|
|
const emailTools = [
|
|
{
|
|
name: "list-emails",
|
|
description: "Lists recent emails from a folder. Results include 'conversationId' which can be passed to 'get-email-thread' to retrieve a full thread. Optional mailbox targets a shared mailbox.",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
folder: {
|
|
type: "string",
|
|
description: "Email folder to list (e.g., 'inbox', 'sent', 'drafts', default: 'inbox')"
|
|
},
|
|
count: {
|
|
anyOf: [{ type: "number" }, { type: "string" }],
|
|
description: "Number of emails to retrieve (default: 10, max: 500). WARNING: Large counts may consume significant context tokens."
|
|
},
|
|
dateFrom: {
|
|
type: "string",
|
|
description: "Start date for email filtering (ISO format: 'YYYY-MM-DD' or relative: 'yesterday', 'last7days')"
|
|
},
|
|
dateTo: {
|
|
type: "string",
|
|
description: "End date for email filtering (ISO format: 'YYYY-MM-DD' or relative: 'today', 'tomorrow')"
|
|
},
|
|
dateRange: {
|
|
type: "string",
|
|
description: "Predefined date range ('today', 'yesterday', 'last7days', 'last30days', 'thisweek', 'lastweek', 'thismonth', 'lastmonth')"
|
|
},
|
|
mailbox: mailboxProp
|
|
},
|
|
required: []
|
|
},
|
|
handler: handleListEmails
|
|
},
|
|
{
|
|
name: "search-emails",
|
|
description: "Search for emails by sender, subject, keywords, or filters. Results include 'conversationId' — pass it to 'get-email-thread' to read the full thread. Optional mailbox targets a shared mailbox. If no matching emails are found, use 'list-emails' to browse recent mail instead.",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
query: {
|
|
type: "string",
|
|
description: "Full-text search query (searches across subject, body, and sender)"
|
|
},
|
|
folder: {
|
|
type: "string",
|
|
description: "Email folder to search in (default: 'inbox'). Use 'list-folders' to discover folder names."
|
|
},
|
|
from: {
|
|
type: "string",
|
|
description: "Filter by sender — can be an email address or display name (e.g. 'john@example.com' or 'John')"
|
|
},
|
|
to: {
|
|
type: "string",
|
|
description: "Filter by recipient email address or display name"
|
|
},
|
|
subject: {
|
|
type: "string",
|
|
description: "Filter by subject line keywords (e.g. 'invoice', 'meeting notes')"
|
|
},
|
|
dateFrom: {
|
|
type: "string",
|
|
description: "Start date for email filtering (ISO format: 'YYYY-MM-DD' or relative: 'yesterday', 'last7days')"
|
|
},
|
|
dateTo: {
|
|
type: "string",
|
|
description: "End date for email filtering (ISO format: 'YYYY-MM-DD' or relative: 'today', 'tomorrow')"
|
|
},
|
|
dateRange: {
|
|
type: "string",
|
|
description: "Predefined date range ('today', 'yesterday', 'last7days', 'last30days', 'thisweek', 'lastweek', 'thismonth', 'lastmonth')"
|
|
},
|
|
hasAttachments: {
|
|
anyOf: [{ type: "boolean" }, { type: "string" }],
|
|
description: "Set true to return only emails that have attachments"
|
|
},
|
|
unreadOnly: {
|
|
anyOf: [{ type: "boolean" }, { type: "string" }],
|
|
description: "Set true to return only unread emails"
|
|
},
|
|
count: {
|
|
anyOf: [{ type: "number" }, { type: "string" }],
|
|
description: "Number of results to return (default: 10, max: 500). WARNING: Large counts may consume significant context tokens."
|
|
},
|
|
strict: {
|
|
anyOf: [{ type: "boolean" }, { type: "string" }],
|
|
description: "Set true to disable the fallback to recent emails when no exact search matches are found"
|
|
},
|
|
mailbox: mailboxProp
|
|
},
|
|
required: []
|
|
},
|
|
handler: handleSearchEmails
|
|
},
|
|
{
|
|
name: "read-email",
|
|
description: "Reads the content of a specific email. If the message came from a shared mailbox, pass the same mailbox value.",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: {
|
|
type: "string",
|
|
description: "ID of the email to read"
|
|
},
|
|
mailbox: mailboxProp
|
|
},
|
|
required: ["id"]
|
|
},
|
|
handler: handleReadEmail
|
|
},
|
|
{
|
|
name: "read-emails",
|
|
description: "Reads the content of multiple emails at once. If IDs came from a shared mailbox, pass the same mailbox value.",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
ids: {
|
|
type: "array",
|
|
items: {
|
|
type: "string"
|
|
},
|
|
description: "Array of email IDs to read (max: 10)"
|
|
},
|
|
mailbox: mailboxProp
|
|
},
|
|
required: ["ids"]
|
|
},
|
|
handler: handleReadMultipleEmails
|
|
},
|
|
{
|
|
name: "send-email",
|
|
description: "Composes and sends a new email. Optional mailbox sends as that shared mailbox (requires Exchange Send As + Mail.Send.Shared). Use onBehalfOf=true for Send on Behalf via me/sendMail with from set.",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
to: {
|
|
type: "string",
|
|
description: "Comma-separated list of recipient email addresses"
|
|
},
|
|
cc: {
|
|
type: "string",
|
|
description: "Comma-separated list of CC recipient email addresses"
|
|
},
|
|
bcc: {
|
|
type: "string",
|
|
description: "Comma-separated list of BCC recipient email addresses"
|
|
},
|
|
subject: {
|
|
type: "string",
|
|
description: "Email subject"
|
|
},
|
|
body: {
|
|
type: "string",
|
|
description: "Email body content (can be plain text or HTML)"
|
|
},
|
|
importance: {
|
|
type: "string",
|
|
description: "Email importance (normal, high, low)",
|
|
enum: ["normal", "high", "low"]
|
|
},
|
|
saveToSentItems: {
|
|
type: "boolean",
|
|
description: "Whether to save the email to sent items"
|
|
},
|
|
mailbox: mailboxProp,
|
|
from: {
|
|
type: "string",
|
|
description: "Optional From SMTP. Defaults to mailbox when mailbox is set."
|
|
},
|
|
onBehalfOf: {
|
|
anyOf: [{ type: "boolean" }, { type: "string" }],
|
|
description: "If true, send via me/sendMail with from=shared (Send on Behalf style). Default false uses users/{mailbox}/sendMail when mailbox is set."
|
|
}
|
|
},
|
|
required: ["to", "subject", "body"]
|
|
},
|
|
handler: handleSendEmail
|
|
}
|
|
];
|
|
|
|
module.exports = {
|
|
emailTools,
|
|
handleListEmails,
|
|
handleSearchEmails,
|
|
handleReadEmail,
|
|
handleReadMultipleEmails,
|
|
handleSendEmail
|
|
};
|