UNPKG

msexchange-mcp

Version:

MCP server for Microsoft Exchange/Outlook email operations via Microsoft Graph API

167 lines (163 loc) 8.51 kB
import { z } from 'zod'; import { MailService } from '../mail/mailService.js'; import accountsConfig from '../config/accountsLoader.js'; export const createMailRuleTool = { name: 'create_mail_rule', description: `Create an Outlook mail rule to automatically organize incoming emails. Features: - Multiple conditions: sender, subject, body keywords, attachments, importance - Multiple actions: move/copy to folder, mark as read, forward, delete, categorize - Rule priority with sequence ordering - Can be enabled/disabled Common use cases: - Auto-file emails from specific senders to folders - Forward urgent emails to team members - Mark newsletters as read automatically - Delete spam based on keywords Examples: - Move emails from boss to Important folder: {"conditions": {"from_addresses": ["boss@company.com"]}, "actions": {"move_to_folder": "Important_folder_id"}} - Auto-categorize project emails: {"conditions": {"subject_contains": ["Project X"]}, "actions": {"add_categories": ["Project X", "Work"]}} - Forward urgent emails: {"conditions": {"importance": "high", "to_me": true}, "actions": {"forward_to": "assistant@company.com"}} Best practices: - Test rules with non-destructive actions first - Use specific conditions to avoid false positives - Order rules by priority (lower sequence numbers run first) - Disable rules when troubleshooting email issues`, parameters: z.object({ user_id: z.string().describe('The user ID or email address'), rule_name: z.string().describe('Name for the mail rule'), conditions: z.object({ from_addresses: z.array(z.string()).optional().describe('Email addresses to match in From field'), subject_contains: z.array(z.string()).optional().describe('Keywords that must be in subject'), body_contains: z.array(z.string()).optional().describe('Keywords that must be in body'), to_me: z.boolean().optional().describe('Email is addressed to me'), cc_me: z.boolean().optional().describe('Email has me in CC'), sent_to: z.array(z.string()).optional().describe('Email is sent to these addresses'), importance: z.enum(['low', 'normal', 'high']).optional().describe('Message importance level'), has_attachments: z.boolean().optional().describe('Email has attachments'), }).describe('Conditions that trigger the rule'), actions: z.object({ move_to_folder: z.string().optional().describe('Folder ID to move emails to'), copy_to_folder: z.string().optional().describe('Folder ID to copy emails to'), add_categories: z.array(z.string()).optional().describe('Categories to add to the email'), mark_as_read: z.boolean().optional().describe('Mark email as read'), mark_importance: z.enum(['low', 'normal', 'high']).optional().describe('Set importance level'), forward_to: z.string().optional().describe('Email address to forward to'), delete_message: z.boolean().optional().describe('Delete the message'), stop_processing: z.boolean().optional().default(true).describe('Stop processing additional rules'), }).describe('Actions to perform when conditions are met'), enabled: z.boolean().optional().default(true).describe('Whether the rule is enabled'), sequence: z.number().optional().describe('Rule execution order (lower numbers run first)'), }), execute: async (params) => { try { const account = accountsConfig.accounts.find(acc => acc.id === params.user_id || acc.email === params.user_id); if (!account) { throw new Error(`User not found: ${params.user_id}`); } const mailService = new MailService(account.email); // Build conditions for Microsoft Graph API format const graphConditions = {}; if (params.conditions.from_addresses?.length > 0) { graphConditions.fromAddresses = params.conditions.from_addresses.map((addr) => ({ emailAddress: { address: addr } })); } if (params.conditions.subject_contains?.length > 0) { graphConditions.subjectContains = params.conditions.subject_contains; } if (params.conditions.body_contains?.length > 0) { graphConditions.bodyContains = params.conditions.body_contains; } if (params.conditions.sent_to?.length > 0) { graphConditions.recipientContains = params.conditions.sent_to.map((addr) => ({ emailAddress: { address: addr } })); } if (params.conditions.importance) { graphConditions.importance = params.conditions.importance; } if (params.conditions.has_attachments !== undefined) { graphConditions.hasAttachments = params.conditions.has_attachments; } if (params.conditions.to_me) { graphConditions.sentToMe = true; } if (params.conditions.cc_me) { graphConditions.sentCcMe = true; } // Build actions for Microsoft Graph API format const graphActions = {}; if (params.actions.move_to_folder) { graphActions.moveToFolder = params.actions.move_to_folder; } if (params.actions.copy_to_folder) { graphActions.copyToFolder = params.actions.copy_to_folder; } if (params.actions.add_categories?.length > 0) { graphActions.assignCategories = params.actions.add_categories; } if (params.actions.mark_as_read !== undefined) { graphActions.markAsRead = params.actions.mark_as_read; } if (params.actions.mark_importance) { graphActions.markImportance = params.actions.mark_importance; } if (params.actions.forward_to) { graphActions.forwardTo = { emailAddress: { address: params.actions.forward_to } }; } if (params.actions.delete_message) { graphActions.delete = true; } if (params.actions.stop_processing !== undefined) { graphActions.stopProcessingRules = params.actions.stop_processing; } const ruleData = { displayName: params.rule_name, sequence: params.sequence || 1, isEnabled: params.enabled !== false, conditions: graphConditions, actions: graphActions, }; const newRule = await mailService.createMailRule(ruleData); return { content: [ { type: 'text', text: JSON.stringify({ success: true, rule: { id: newRule.id, displayName: newRule.displayName, sequence: newRule.sequence, isEnabled: newRule.isEnabled, conditions: newRule.conditions, actions: newRule.actions, }, message: `Successfully created mail rule '${params.rule_name}'`, usage_tips: [ 'Test the rule with a few emails before enabling for all mail', 'Use lower sequence numbers for higher priority rules', 'Consider using "stop_processing: false" to allow multiple rules to apply', 'Check rule execution order if emails aren\'t being processed as expected' ] }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error creating mail rule: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } }, }; //# sourceMappingURL=createMailRule.js.map