/** * Read email functionality */ const config = require('../config'); const { callGraphAPI } = require('../utils/graph-api'); const { ensureAuthenticated } = require('../auth'); const { cleanBody } = require('../utils/bodyParser'); const { formatDateTime } = require('../utils/time-formatter'); const { normalizeMailbox, buildPath, withMailboxHeaders } = require('../utils/mailbox'); /** * Read email handler * @param {object} args - Tool arguments * @returns {object} - MCP response */ async function handleReadEmail(args) { const emailId = args.id; const mb = normalizeMailbox(args.mailbox); if (!emailId) { return { content: [{ type: "text", text: "Email ID is required." }] }; } try { const accessToken = await ensureAuthenticated(); // Do not pre-encode the ID — callGraphAPI encodes each path segment once. const endpoint = buildPath(mb, `messages/${emailId}`); const queryParams = { $select: config.EMAIL_DETAIL_FIELDS }; const opts = { headers: withMailboxHeaders(mb) }; try { const email = await callGraphAPI(accessToken, 'GET', endpoint, null, queryParams, opts); if (!email) { return { content: [ { type: "text", text: `Email with ID ${emailId} not found.` } ] }; } 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 = formatDateTime(email.receivedDateTime); let body = ''; if (email.body) { body = cleanBody(email.body.content); } else { body = cleanBody(email.bodyPreview) || 'No content'; } const mailboxLine = mb.kind === 'user' ? `Mailbox: ${mb.smtpOrUpn}\n` : ''; const formattedEmail = `${mailboxLine}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}`; return { content: [ { type: "text", text: formattedEmail } ] }; } catch (error) { console.error(`Error reading email: ${error.message}`); if (error.message.includes("doesn't belong to the targeted mailbox")) { return { content: [ { type: "text", text: `The email ID seems invalid or doesn't belong to the targeted mailbox${mb.kind === 'user' ? ` (${mb.smtpOrUpn})` : ''}. Pass the same mailbox used when listing/searching, or try a different email ID.` } ] }; } else { return { content: [ { type: "text", text: `Failed to read email: ${error.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 accessing email: ${error.message}` }] }; } } module.exports = handleReadEmail;