UNPKG

outlook-mcp

Version:

Comprehensive MCP server for Claude to access Microsoft Outlook and Teams via Microsoft Graph API - including Email, Calendar, Contacts, Tasks, Teams, Chats, and Online Meetings

164 lines (143 loc) 4.35 kB
/** * Move emails functionality */ const { callGraphAPI } = require('../utils/graph-api'); const { ensureAuthenticated } = require('../auth'); const { getFolderIdByName } = require('../email/folder-utils'); /** * Move emails handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleMoveEmails(args) { const emailIds = args.emailIds || ''; const targetFolder = args.targetFolder || ''; const sourceFolder = args.sourceFolder || ''; if (!emailIds) { return { content: [{ type: "text", text: "Email IDs are required. Please provide a comma-separated list of email IDs to move." }] }; } if (!targetFolder) { return { content: [{ type: "text", text: "Target folder name is required." }] }; } try { // Get access token const accessToken = await ensureAuthenticated(); // Parse email IDs const ids = emailIds.split(',').map(id => id.trim()).filter(id => id); if (ids.length === 0) { return { content: [{ type: "text", text: "No valid email IDs provided." }] }; } // Move emails const result = await moveEmailsToFolder(accessToken, ids, targetFolder, sourceFolder); return { content: [{ type: "text", text: result.message }] }; } 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 moving emails: ${error.message}` }] }; } } /** * Move emails to a folder * @param {string} accessToken - Access token * @param {Array<string>} emailIds - Array of email IDs to move * @param {string} targetFolderName - Name of the target folder * @param {string} sourceFolderName - Name of the source folder (optional) * @returns {Promise<object>} - Result object with status and message */ async function moveEmailsToFolder(accessToken, emailIds, targetFolderName, sourceFolderName) { try { // Get the target folder ID const targetFolderId = await getFolderIdByName(accessToken, targetFolderName); if (!targetFolderId) { return { success: false, message: `Target folder "${targetFolderName}" not found. Please specify a valid folder name.` }; } // Track successful and failed moves const results = { successful: [], failed: [] }; // Process each email one by one to handle errors independently for (const emailId of emailIds) { try { // Move the email await callGraphAPI( accessToken, 'POST', `me/messages/${emailId}/move`, { destinationId: targetFolderId } ); results.successful.push(emailId); } catch (error) { console.error(`Error moving email ${emailId}: ${error.message}`); results.failed.push({ id: emailId, error: error.message }); } } // Generate result message let message = ''; if (results.successful.length > 0) { message += `Successfully moved ${results.successful.length} email(s) to "${targetFolderName}".`; } if (results.failed.length > 0) { if (message) message += '\n\n'; message += `Failed to move ${results.failed.length} email(s). Errors:`; // Show first few errors with details const maxErrors = Math.min(results.failed.length, 3); for (let i = 0; i < maxErrors; i++) { const failure = results.failed[i]; message += `\n- Email ${i+1}: ${failure.error}`; } // If there are more errors, just mention the count if (results.failed.length > maxErrors) { message += `\n...and ${results.failed.length - maxErrors} more.`; } } return { success: results.successful.length > 0, message, results }; } catch (error) { console.error(`Error in moveEmailsToFolder: ${error.message}`); throw error; } } module.exports = handleMoveEmails;