/** * Read multiple emails functionality */ const config = require('../config'); const { callGraphAPI } = require('../utils/graph-api'); const { ensureAuthenticated } = require('../auth'); const { cleanBody } = require('../utils/bodyParser'); /** * Format a single email for display * @param {object} email - Email object from Graph API * @param {string} emailId - Email ID for error context * @returns {string} - Formatted email text */ function formatEmail(email, emailId) { if (!email) { return `Email ID ${emailId}: Not found or inaccessible`; } try { // Format sender, recipients, etc. const sender = email.from ? `${email.from.emailAddress.name} (${email.from.emailAddress.address})` : 'Unknown'; const to = email.toRecipients ? email.toRecipients.map(r => `${r.emailAddress.name} (${r.emailAddress.address})`).join(", ") : 'None'; const cc = email.ccRecipients && email.ccRecipients.length > 0 ? email.ccRecipients.map(r => `${r.emailAddress.name} (${r.emailAddress.address})`).join(", ") : 'None'; const bcc = email.bccRecipients && email.bccRecipients.length > 0 ? email.bccRecipients.map(r => `${r.emailAddress.name} (${r.emailAddress.address})`).join(", ") : 'None'; const date = new Date(email.receivedDateTime).toLocaleString(); // Extract and clean body content (cleanBody handles both HTML and plain text) let body = ''; if (email.body) { body = cleanBody(email.body.content); } else { body = cleanBody(email.bodyPreview) || 'No content'; } // Format the email return `From: ${sender} To: ${to} ${cc !== 'None' ? `CC: ${cc}\n` : ''}${bcc !== 'None' ? `BCC: ${bcc}\n` : ''}Subject: ${email.subject} Date: ${date} Importance: ${email.importance || 'normal'} Has Attachments: ${email.hasAttachments ? 'Yes' : 'No'} ${body}`; } catch (error) { return `Email ID ${emailId}: Error formatting email - ${error.message}`; } } /** * Read multiple emails handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleReadMultipleEmails(args) { const emailIds = args.ids; if (!emailIds || !Array.isArray(emailIds) || emailIds.length === 0) { return { content: [{ type: "text", text: "Email IDs array is required and must contain at least one ID." }] }; } // Limit the number of emails to prevent overwhelming responses const maxEmails = 10; if (emailIds.length > maxEmails) { return { content: [{ type: "text", text: `Too many email IDs provided. Maximum allowed is ${maxEmails}, but ${emailIds.length} were provided.` }] }; } try { // Get access token const accessToken = await ensureAuthenticated(); // Create concurrent API calls for all email IDs const emailPromises = emailIds.map(async (emailId) => { try { const endpoint = `me/messages/${encodeURIComponent(emailId)}`; const queryParams = { $select: config.EMAIL_DETAIL_FIELDS }; const email = await callGraphAPI(accessToken, 'GET', endpoint, null, queryParams); return { emailId, email, error: null }; } catch (error) { console.error(`Error reading email ${emailId}: ${error.message}`); return { emailId, email: null, error: error.message }; } }); // Wait for all API calls to complete const results = await Promise.all(emailPromises); // Format all emails const formattedEmails = results.map((result, index) => { const emailNumber = index + 1; const separator = "=".repeat(80); if (result.error) { return `${separator} EMAIL ${emailNumber} (ID: ${result.emailId}) ${separator} Error: ${result.error}`; } else { const formattedEmail = formatEmail(result.email, result.emailId); return `${separator} EMAIL ${emailNumber} (ID: ${result.emailId}) ${separator} ${formattedEmail}`; } }); // Count successful vs failed reads const successCount = results.filter(r => !r.error && r.email).length; const errorCount = results.filter(r => r.error || !r.email).length; const summary = `Retrieved ${successCount} email(s) successfully${errorCount > 0 ? `, ${errorCount} failed` : ''}. `; return { content: [ { type: "text", text: summary + formattedEmails.join('\n\n') } ] }; } 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 accessing emails: ${error.message}` }] }; } } module.exports = handleReadMultipleEmails;