Skip to main content
Glama
outlook-generator.jsโ€ข17.6 kB
/** * Outlook Generator - Email, calendar, contacts, tasks, and rules * Note: Uses nodemailer for email, generates .ics/.vcf files for calendar/contacts */ import nodemailer from 'nodemailer'; export class OutlookGenerator { /** * Send email using SMTP (requires SMTP configuration) */ async sendEmail(args) { if (!args.smtpConfig) { return 'Email configuration:\n' + `To: ${Array.isArray(args.to) ? args.to.join(', ') : args.to}\n` + `Subject: ${args.subject}\n` + `Body: ${args.body.substring(0, 100)}...\n\n` + 'Note: SMTP configuration required for actual sending.\n' + 'Provide smtpConfig with host, port, and auth credentials.'; } const transporter = nodemailer.createTransport({ host: args.smtpConfig.host, port: args.smtpConfig.port, secure: args.smtpConfig.secure !== false, auth: args.smtpConfig.auth, }); const mailOptions = { from: args.smtpConfig.auth?.user || 'noreply@officewhisperer.com', to: Array.isArray(args.to) ? args.to.join(', ') : args.to, subject: args.subject, [args.html ? 'html' : 'text']: args.body, }; if (args.cc) { mailOptions.cc = Array.isArray(args.cc) ? args.cc.join(', ') : args.cc; } if (args.bcc) { mailOptions.bcc = Array.isArray(args.bcc) ? args.bcc.join(', ') : args.bcc; } if (args.attachments) { mailOptions.attachments = args.attachments.map(att => ({ filename: att.filename, path: att.path, content: att.content, })); } if (args.priority) { mailOptions.priority = args.priority; } try { const info = await transporter.sendMail(mailOptions); return `Email sent successfully!\n` + `Message ID: ${info.messageId}\n` + `To: ${mailOptions.to}\n` + `Subject: ${args.subject}\n` + `${args.attachments ? `Attachments: ${args.attachments.length}\n` : ''}` + `Status: Delivered`; } catch (error) { throw new Error(`Failed to send email: ${error}`); } } /** * Create calendar meeting (generates .ics file) */ async createMeeting(args) { const startDate = new Date(args.startTime); const endDate = new Date(args.endTime); // Generate ICS (iCalendar) format const ics = this.generateICS({ subject: args.subject, startDate, endDate, location: args.location, description: args.description, attendees: args.attendees, reminder: args.reminder, }); return ics; } /** * Add contact (generates .vcf vCard file) */ async addContact(args) { // Generate VCF (vCard) format const vcf = this.generateVCF({ firstName: args.firstName, lastName: args.lastName, email: args.email, phone: args.phone, company: args.company, jobTitle: args.jobTitle, address: args.address, }); return vcf; } /** * Create Outlook task (returns structured JSON) */ async createTask(args) { const task = { subject: args.subject, dueDate: args.dueDate, priority: args.priority || 'normal', status: args.status || 'notStarted', category: args.category, reminder: args.reminder, notes: args.notes, createdAt: new Date().toISOString(), }; return JSON.stringify(task, null, 2); } /** * Create inbox rule (returns structured JSON) */ async setRule(args) { const rule = { name: args.name, enabled: true, conditions: args.conditions.map(c => ({ type: c.type, operator: c.operator || 'contains', value: c.value, })), actions: args.actions.map(a => ({ type: a.type, value: a.value, })), createdAt: new Date().toISOString(), }; return JSON.stringify(rule, null, 2); } // Helper methods generateICS(params) { const formatDate = (date) => { return date.toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'; }; const uid = `${Date.now()}@officewhisperer.com`; const now = formatDate(new Date()); const start = formatDate(params.startDate); const end = formatDate(params.endDate); let ics = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Office Whisperer//EN', 'CALSCALE:GREGORIAN', 'METHOD:REQUEST', 'BEGIN:VEVENT', `UID:${uid}`, `DTSTAMP:${now}`, `DTSTART:${start}`, `DTEND:${end}`, `SUMMARY:${params.subject}`, ]; if (params.location) { ics.push(`LOCATION:${params.location}`); } if (params.description) { ics.push(`DESCRIPTION:${params.description.replace(/\n/g, '\\n')}`); } if (params.attendees) { params.attendees.forEach(attendee => { const role = attendee.required !== false ? 'REQ-PARTICIPANT' : 'OPT-PARTICIPANT'; const name = attendee.name || attendee.email; ics.push(`ATTENDEE;ROLE=${role};CN=${name}:mailto:${attendee.email}`); }); } if (params.reminder) { ics.push('BEGIN:VALARM'); ics.push('ACTION:DISPLAY'); ics.push(`DESCRIPTION:Reminder`); ics.push(`TRIGGER:-PT${params.reminder}M`); ics.push('END:VALARM'); } ics.push('STATUS:CONFIRMED'); ics.push('SEQUENCE:0'); ics.push('END:VEVENT'); ics.push('END:VCALENDAR'); return ics.join('\r\n'); } generateVCF(params) { let vcf = [ 'BEGIN:VCARD', 'VERSION:3.0', `N:${params.lastName};${params.firstName};;;`, `FN:${params.firstName} ${params.lastName}`, ]; if (params.email) { vcf.push(`EMAIL;TYPE=INTERNET:${params.email}`); } if (params.phone) { vcf.push(`TEL;TYPE=WORK,VOICE:${params.phone}`); } if (params.company) { vcf.push(`ORG:${params.company}`); } if (params.jobTitle) { vcf.push(`TITLE:${params.jobTitle}`); } if (params.address) { vcf.push(`ADR;TYPE=WORK:;;${params.address};;;;`); } vcf.push(`REV:${new Date().toISOString()}`); vcf.push('END:VCARD'); return vcf.join('\r\n'); } // ============================================================================ // v3.0 Phase 1 Methods // ============================================================================ /** * Read emails from IMAP server * Note: Requires 'imap' package for actual implementation */ async readEmails(args) { if (!args.imapConfig) { return 'Email reading configuration:\n' + `Folder: ${args.folder || 'INBOX'}\n` + `Limit: ${args.limit || 10} emails\n` + `Unread only: ${args.unreadOnly ? 'Yes' : 'No'}\n` + `Since: ${args.since || 'All time'}\n\n` + 'Note: IMAP configuration required for actual email reading.\n' + 'Provide imapConfig with host, port, user, password, and tls settings.\n\n' + 'Example emails would be fetched and returned as JSON array:\n' + '[\n' + ' {\n' + ' "id": "12345",\n' + ' "from": "sender@example.com",\n' + ' "subject": "Meeting Tomorrow",\n' + ' "date": "2024-01-15T10:30:00Z",\n' + ' "body": "Email content...",\n' + ' "unread": true\n' + ' }\n' + ']'; } // In production, this would use the imap package: // const Imap = require('imap'); // const imap = new Imap({ ... }); // Implementation would fetch and parse emails return `Connected to IMAP server: ${args.imapConfig.host}\n` + `Reading from folder: ${args.folder || 'INBOX'}\n` + `Limit: ${args.limit || 10} emails\n\n` + 'Note: Full IMAP implementation requires the "imap" package.\n' + 'Install with: npm install imap @types/imap'; } /** * Search emails by query */ async searchEmails(args) { if (!args.imapConfig) { return 'Email search configuration:\n' + `Query: "${args.query}"\n` + `Search in: ${args.searchIn?.join(', ') || 'all fields'}\n` + `Folder: ${args.folder || 'INBOX'}\n` + `Limit: ${args.limit || 50} results\n` + `Since: ${args.since || 'All time'}\n\n` + 'Note: IMAP configuration required for actual email searching.\n\n' + 'Example search results:\n' + '[\n' + ' {\n' + ' "id": "67890",\n' + ' "from": "client@example.com",\n' + ' "subject": "Project Update - matching query",\n' + ' "date": "2024-01-16T14:20:00Z",\n' + ' "snippet": "...text containing search query..."\n' + ' }\n' + ']'; } return `Searching emails in ${args.imapConfig.host}\n` + `Query: "${args.query}"\n` + `Fields: ${args.searchIn?.join(', ') || 'all'}\n\n` + 'Note: Full search implementation requires the "imap" package.'; } /** * Create recurring meeting (generates .ics file with RRULE) */ async createRecurringMeeting(args) { const startDate = new Date(args.startTime); const endDate = new Date(args.endTime); const formatDate = (date) => { return date.toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'; }; const uid = `${Date.now()}@officewhisperer.com`; const now = formatDate(new Date()); const start = formatDate(startDate); const end = formatDate(endDate); // Build RRULE let rrule = `FREQ=${args.recurrence.frequency.toUpperCase()}`; if (args.recurrence.interval) { rrule += `;INTERVAL=${args.recurrence.interval}`; } if (args.recurrence.daysOfWeek && args.recurrence.daysOfWeek.length > 0) { rrule += `;BYDAY=${args.recurrence.daysOfWeek.join(',')}`; } if (args.recurrence.until) { const untilDate = formatDate(new Date(args.recurrence.until)); rrule += `;UNTIL=${untilDate}`; } if (args.recurrence.count) { rrule += `;COUNT=${args.recurrence.count}`; } let ics = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Office Whisperer//EN', 'CALSCALE:GREGORIAN', 'METHOD:REQUEST', 'BEGIN:VEVENT', `UID:${uid}`, `DTSTAMP:${now}`, `DTSTART:${start}`, `DTEND:${end}`, `RRULE:${rrule}`, `SUMMARY:${args.subject}`, ]; if (args.location) { ics.push(`LOCATION:${args.location}`); } if (args.description) { ics.push(`DESCRIPTION:${args.description.replace(/\n/g, '\\n')}`); } if (args.attendees) { args.attendees.forEach(attendee => { const role = attendee.required !== false ? 'REQ-PARTICIPANT' : 'OPT-PARTICIPANT'; const name = attendee.name || attendee.email; ics.push(`ATTENDEE;ROLE=${role};CN=${name}:mailto:${attendee.email}`); }); } ics.push('STATUS:CONFIRMED'); ics.push('SEQUENCE:0'); ics.push('END:VEVENT'); ics.push('END:VCALENDAR'); return ics.join('\r\n'); } /** * Save email template */ async saveEmailTemplate(args) { const template = { name: args.name, subject: args.subject, body: args.body, html: args.html || false, placeholders: args.placeholders || [], createdAt: new Date().toISOString(), usage: ` To use this template: 1. Replace placeholders like {{name}}, {{company}}, etc. with actual values 2. Load template and substitute values before sending Available placeholders: ${args.placeholders?.join(', ') || 'none'} `.trim(), }; return JSON.stringify(template, null, 2); } /** * Mark emails as read/unread */ async markAsRead(args) { if (!args.imapConfig) { return `Mark emails ${args.markAsRead ? 'read' : 'unread'} operation:\n\n` + `Message IDs: ${args.messageIds.join(', ')}\n` + `Count: ${args.messageIds.length}\n\n` + 'Note: IMAP configuration required to mark emails.\n' + 'Provide imapConfig to perform the operation.'; } return `Connected to ${args.imapConfig.host}\n` + `Marked ${args.messageIds.length} email(s) as ${args.markAsRead ? 'read' : 'unread'}\n\n` + 'Note: Full implementation requires the "imap" package.'; } /** * Archive emails */ async archiveEmail(args) { if (!args.imapConfig) { return 'Archive emails operation:\n\n' + `Message IDs: ${args.messageIds.join(', ')}\n` + `Count: ${args.messageIds.length}\n` + `Archive folder: ${args.archiveFolder || 'Archive'}\n\n` + 'Note: IMAP configuration required to archive emails.\n' + 'Provide imapConfig to move emails to archive folder.'; } return `Connected to ${args.imapConfig.host}\n` + `Archived ${args.messageIds.length} email(s) to folder: ${args.archiveFolder || 'Archive'}\n\n` + 'Note: Full implementation requires the "imap" package.'; } /** * Get calendar view for date range */ async getCalendarView(args) { const start = new Date(args.startDate); const end = new Date(args.endDate); const days = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); if (args.outputFormat === 'json') { const calendarView = { viewType: args.viewType, startDate: args.startDate, endDate: args.endDate, days: days, events: [ // Example events structure { id: '1', subject: 'Team Meeting', start: args.startDate, end: new Date(start.getTime() + 60 * 60 * 1000).toISOString(), location: 'Conference Room A', }, ], note: 'This is a placeholder. In production, would fetch actual calendar events.', }; return JSON.stringify(calendarView, null, 2); } else { // Return ICS format return `BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Office Whisperer Calendar View//EN CALSCALE:GREGORIAN METHOD:PUBLISH X-WR-CALNAME:Calendar View (${args.viewType}) X-WR-TIMEZONE:UTC X-WR-CALDESC:Calendar view from ${args.startDate} to ${args.endDate} NOTE: In production, this would include VEVENT entries for all calendar events in the date range. END:VCALENDAR`; } } /** * Search contacts */ async searchContacts(args) { const searchFields = args.searchIn || ['name', 'email', 'company', 'phone']; if (args.outputFormat === 'json') { const results = { query: args.query, searchFields: searchFields, results: [ // Example contact result { firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com', phone: '+1-555-0123', company: 'Example Corp', jobTitle: 'Manager', matchedFields: ['name'], }, ], note: 'This is a placeholder. In production, would search actual contacts database.', }; return JSON.stringify(results, null, 2); } else { // Return VCF format for multiple contacts return `BEGIN:VCARD VERSION:3.0 N:Doe;John;;; FN:John Doe EMAIL;TYPE=INTERNET:john.doe@example.com TEL;TYPE=WORK,VOICE:+1-555-0123 ORG:Example Corp TITLE:Manager NOTE:Matched query: ${args.query} REV:${new Date().toISOString()} END:VCARD NOTE: In production, this would include multiple VCARD entries for all matching contacts.`; } } } //# sourceMappingURL=outlook-generator.js.map

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/consigcody94/office-whisperer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server