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.
101 lines
3.3 KiB
JavaScript
101 lines
3.3 KiB
JavaScript
const { formatDateTime } = require('../utils/time-formatter');
|
|
|
|
/**
|
|
* List emails functionality
|
|
*/
|
|
const config = require('../config');
|
|
const { callGraphAPI } = require('../utils/graph-api');
|
|
const { ensureAuthenticated } = require('../auth');
|
|
const { buildODataFilter, buildDateFilter } = require('../utils/odata-helpers');
|
|
const { resolveFolderPath } = require('./folder-utils');
|
|
const { normalizeMailbox, withMailboxHeaders } = require('../utils/mailbox');
|
|
|
|
/**
|
|
* List emails handler
|
|
* @param {object} args - Tool arguments
|
|
* @returns {object} - MCP response
|
|
*/
|
|
async function handleListEmails(args) {
|
|
const folder = args.folder || "inbox";
|
|
const count = Math.min(parseInt(args.count, 10) || 10, config.MAX_RESULT_COUNT);
|
|
const mb = normalizeMailbox(args.mailbox);
|
|
|
|
try {
|
|
const accessToken = await ensureAuthenticated();
|
|
const endpoint = await resolveFolderPath(accessToken, folder, mb);
|
|
const opts = { headers: withMailboxHeaders(mb) };
|
|
|
|
const queryParams = {
|
|
$top: count,
|
|
$orderby: 'receivedDateTime desc',
|
|
$select: config.EMAIL_SELECT_FIELDS
|
|
};
|
|
|
|
const dateConditions = buildDateFilter(args.dateFrom, args.dateTo, args.dateRange);
|
|
if (dateConditions.length > 0) {
|
|
queryParams.$filter = buildODataFilter(dateConditions);
|
|
}
|
|
|
|
const response = await callGraphAPI(accessToken, 'GET', endpoint, null, queryParams, opts);
|
|
|
|
if (!response.value || response.value.length === 0) {
|
|
const where = mb.kind === 'user' ? `${folder} (${mb.smtpOrUpn})` : folder;
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `No emails found in ${where}.`
|
|
}]
|
|
};
|
|
}
|
|
|
|
const emailList = response.value.map((email, index) => {
|
|
const sender = email.from ? email.from.emailAddress : { name: 'Unknown', address: 'unknown' };
|
|
const date = formatDateTime(email.receivedDateTime);
|
|
const readStatus = email.isRead ? '' : '[UNREAD] ';
|
|
const convLine = email.conversationId ? `ConversationID: ${email.conversationId}\n` : '';
|
|
|
|
return `${index + 1}. ${readStatus}${date} - From: ${sender.name} (${sender.address})\nSubject: ${email.subject}\nID: ${email.id}\n${convLine}`;
|
|
}).join("\n");
|
|
|
|
let resultMessage = `Found ${response.value.length} emails in ${folder}`;
|
|
if (mb.kind === 'user') {
|
|
resultMessage += ` [mailbox: ${mb.smtpOrUpn}]`;
|
|
}
|
|
|
|
if (args.dateRange) {
|
|
resultMessage += ` (${args.dateRange})`;
|
|
} else if (args.dateFrom || args.dateTo) {
|
|
const dateInfo = [];
|
|
if (args.dateFrom) dateInfo.push(`from: ${args.dateFrom}`);
|
|
if (args.dateTo) dateInfo.push(`to: ${args.dateTo}`);
|
|
resultMessage += ` (${dateInfo.join(', ')})`;
|
|
}
|
|
|
|
resultMessage += `:\n\n${emailList}`;
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: resultMessage
|
|
}]
|
|
};
|
|
} catch (error) {
|
|
if (error.message === 'Authentication required') {
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
}]
|
|
};
|
|
}
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `Error listing emails: ${error.message}`
|
|
}]
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = handleListEmails;
|