Skip to main content
Glama
conversation-based-organization.js12.1 kB
#!/usr/bin/env node import { FastMailClient } from './src/fastmail-client.js'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); async function conversationBasedOrganization() { console.log('💬 CONVERSATION-BASED ORGANIZATION\n'); console.log('Logic: If you replied → move to appropriate folder'); console.log(' If you haven\'t replied → keep in inbox\n'); const client = new FastMailClient( process.env.FASTMAIL_API_TOKEN, 'clark@clarkeverson.com', 'clark@clarkeverson.com', 'clarkeverson.com', 'https://api.fastmail.com/jmap/session' ); try { await client.authenticate(); const mailboxes = await client.getMailboxes(); const sentMailbox = mailboxes.find(mb => mb.name === 'Sent'); const inboxMailbox = mailboxes.find(mb => mb.name === 'Inbox'); if (!sentMailbox || !inboxMailbox) { console.log('❌ Could not find Sent or Inbox folders'); return; } console.log('📤 Analyzing your sent emails to identify completed conversations...'); // Get ALL your sent emails to build comprehensive conversation map let allSentEmails = []; let sentPosition = 0; while (sentPosition < sentMailbox.totalEmails) { const sentBatch = await client.getEmails(sentMailbox.id, 100, sentPosition); if (!sentBatch?.emails?.length) break; allSentEmails.push(...sentBatch.emails); sentPosition += sentBatch.emails.length; console.log(` 📤 Loaded ${allSentEmails.length} sent emails...`); if (allSentEmails.length >= 500) break; // Limit for performance } // Build conversation tracking const repliedToEmails = new Set(); const repliedToSubjects = new Set(); const repliedToDomains = new Set(); allSentEmails.forEach(sentEmail => { // Track who you replied to if (sentEmail.to) { sentEmail.to.forEach(recipient => { repliedToEmails.add(recipient.email.toLowerCase()); const domain = recipient.email.split('@')[1]?.toLowerCase(); if (domain) repliedToDomains.add(domain); }); } // Track subjects you replied to (clean subject lines) if (sentEmail.subject) { const cleanSubject = sentEmail.subject .replace(/^(re:|fwd?:)\s*/i, '') .toLowerCase() .trim(); if (cleanSubject.length > 3) { repliedToSubjects.add(cleanSubject); } } }); console.log(`📧 You've replied to ${repliedToEmails.size} email addresses`); console.log(`📝 You've replied to ${repliedToSubjects.size} different subjects`); console.log(`🌐 You've replied to ${repliedToDomains.size} domains`); // Get target folders const infoParent = mailboxes.find(mb => mb.name === 'Information'); const financialParent = mailboxes.find(mb => mb.name === 'Financial'); const commerceParent = mailboxes.find(mb => mb.name === 'Commerce'); const professionalParent = mailboxes.find(mb => mb.name === 'Professional'); const personalParent = mailboxes.find(mb => mb.name === 'Personal'); const targets = { 'Information/Newsletters': mailboxes.find(mb => mb.parentId === infoParent?.id && mb.name === 'Newsletters'), 'Information/News': mailboxes.find(mb => mb.parentId === infoParent?.id && mb.name === 'News'), 'Financial/Receipts': mailboxes.find(mb => mb.parentId === financialParent?.id && mb.name === 'Receipts'), 'Financial/Banking': mailboxes.find(mb => mb.parentId === financialParent?.id && mb.name === 'Banking'), 'Commerce/Orders': mailboxes.find(mb => mb.parentId === commerceParent?.id && mb.name === 'Orders'), 'Professional/GitHub': mailboxes.find(mb => mb.parentId === professionalParent?.id && mb.name === 'GitHub'), 'Professional/Security': mailboxes.find(mb => mb.parentId === professionalParent?.id && mb.name === 'Security'), 'Personal/Health': mailboxes.find(mb => mb.parentId === personalParent?.id && mb.name === 'Health'), 'Personal/Travel': mailboxes.find(mb => mb.parentId === personalParent?.id && mb.name === 'Travel'), 'Personal': personalParent, 'Spam': mailboxes.find(mb => mb.name === 'Spam') }; console.log(`\n📥 Processing ${inboxMailbox.totalEmails} inbox emails...`); console.log('='.repeat(80)); let position = 0; let movedToFolders = 0; let keptInInbox = 0; let spamMoved = 0; while (position < inboxMailbox.totalEmails) { const emailResult = await client.getEmails(inboxMailbox.id, 25, position); if (!emailResult?.emails?.length) break; console.log(`\n📧 Batch ${Math.floor(position/25) + 1}: emails ${position + 1}-${position + emailResult.emails.length}`); for (const email of emailResult.emails) { try { const sender = email.from?.[0]?.email?.toLowerCase() || ''; const subject = email.subject || ''; const cleanSubject = subject.replace(/^(re:|fwd?:)\s*/i, '').toLowerCase().trim(); const senderDomain = sender.split('@')[1]?.toLowerCase() || ''; // Check if you've replied to this conversation const hasReplied = repliedToEmails.has(sender) || repliedToSubjects.has(cleanSubject) || (senderDomain && repliedToDomains.has(senderDomain) && !sender.includes('noreply') && !sender.includes('no-reply')); // Categorize based on whether you've replied if (hasReplied) { // You've replied - move to appropriate folder let targetPath = null; // Categorize based on content if ( // Financial sender.includes('bank') || sender.includes('paypal') || sender.includes('stripe') || sender.includes('chase') || sender.includes('fidelity') || sender.includes('schwab') || sender.includes('mortgage') || sender.includes('loan') || sender.includes('credit') || subject.toLowerCase().includes('payment') || subject.toLowerCase().includes('receipt') || subject.toLowerCase().includes('invoice') || subject.toLowerCase().includes('statement') || subject.toLowerCase().includes('mortgage') || subject.toLowerCase().includes('refinance') ) { targetPath = subject.toLowerCase().includes('statement') || subject.toLowerCase().includes('balance') ? 'Financial/Banking' : 'Financial/Receipts'; } // Commerce else if ( sender.includes('amazon') || sender.includes('etsy') || sender.includes('shop') || sender.includes('order') || sender.includes('commerce') || subject.toLowerCase().includes('order') || subject.toLowerCase().includes('shipped') || subject.toLowerCase().includes('delivery') || subject.toLowerCase().includes('subscription') ) { targetPath = 'Commerce/Orders'; } // Professional else if ( sender.includes('github') || sender.includes('slack') || sender.includes('google') || sender.includes('microsoft') || sender.includes('work') || sender.includes('job') || subject.toLowerCase().includes('github') || subject.toLowerCase().includes('work') || subject.toLowerCase().includes('job') || subject.toLowerCase().includes('professional') ) { targetPath = 'Professional/GitHub'; } // Health else if ( sender.includes('health') || sender.includes('medical') || sender.includes('doctor') || sender.includes('hospital') || sender.includes('clinic') || subject.toLowerCase().includes('health') || subject.toLowerCase().includes('medical') || subject.toLowerCase().includes('appointment') || subject.toLowerCase().includes('doctor') ) { targetPath = 'Personal/Health'; } // Travel else if ( sender.includes('travel') || sender.includes('flight') || sender.includes('hotel') || sender.includes('booking') || sender.includes('airbnb') || subject.toLowerCase().includes('travel') || subject.toLowerCase().includes('flight') || subject.toLowerCase().includes('hotel') || subject.toLowerCase().includes('booking') ) { targetPath = 'Personal/Travel'; } // Personal (general personal communications) else if ( // Personal email domains (sender.includes('@gmail.com') || sender.includes('@yahoo.com') || sender.includes('@hotmail.com') || sender.includes('@outlook.com') || sender.includes('@icloud.com')) && !sender.includes('noreply') && !subject.toLowerCase().includes('unsubscribe') ) { targetPath = 'Personal'; } // Information/Newsletters (default for automated content you've replied to) else { targetPath = 'Information/Newsletters'; } if (targetPath && targets[targetPath]) { await client.moveEmailsToMailbox([email.id], targets[targetPath].id); movedToFolders++; console.log(` ✅ [REPLIED] ${subject.substring(0, 40)}... → ${targetPath}`); } } else { // You haven't replied - check if it's spam or legitimate // SPAM - Move obvious spam if ( subject.toLowerCase().includes('tea trick') || subject.toLowerCase().includes('blood sugar') || subject.toLowerCase().includes('weight loss') || subject.toLowerCase().includes('prostate') || subject.toLowerCase().includes('vertigo') || subject.toLowerCase().includes('memory loss') || subject.toLowerCase().includes('milf') || subject.toLowerCase().includes('wild night') || sender.includes('@cube.dochltrowapp.com') || sender.includes('@petsitedeal.com') || sender.includes('@blanco17.com') ) { if (targets['Spam']) { await client.moveEmailsToMailbox([email.id], targets['Spam'].id); spamMoved++; console.log(` 🗑️ [SPAM] ${subject.substring(0, 40)}... → Spam`); } } else { // Not spam and you haven't replied - keep in inbox keptInInbox++; console.log(` 📥 [KEEP] ${subject.substring(0, 40)}... (awaiting response)`); } } } catch (error) { console.log(` ❌ Error processing: ${error.message}`); } } position += emailResult.emails.length; await new Promise(resolve => setTimeout(resolve, 1500)); } console.log('\n🎉 CONVERSATION-BASED ORGANIZATION COMPLETE!'); console.log('='.repeat(60)); console.log(`✅ Completed conversations moved to folders: ${movedToFolders}`); console.log(`📥 Awaiting response (kept in inbox): ${keptInInbox}`); console.log(`🗑️ Spam moved: ${spamMoved}`); console.log(`📧 Total processed: ${movedToFolders + keptInInbox + spamMoved}`); console.log('\n✅ INBOX NOW CONTAINS ONLY:'); console.log('• Emails you haven\'t responded to yet'); console.log('• Legitimate emails awaiting your action'); console.log('• True "actionable" content'); } catch (error) { console.log('❌ Error:', error.message); } } conversationBasedOrganization().catch(console.error);

Latest Blog Posts

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/gr3enarr0w/fastmail-mcp-server'

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