Skip to main content
Glama
migrate-all-emails-fixed.jsβ€’7.16 kB
#!/usr/bin/env node import { FastMailClient } from './src/fastmail-client.js'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); async function migrateAllEmailsFixed() { console.log('πŸ“§ MIGRATING ALL EMAILS TO HIERARCHICAL STRUCTURE (FIXED)\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(); console.log('βœ… Authenticated\n'); const mailboxes = await client.getMailboxes(); console.log(`πŸ“‹ Found ${mailboxes.length} mailboxes\n`); // Define migrations - old folders to new hierarchical structure const migrations = [ { from: 'Newsletter', to: 'Information/Newsletters' }, { from: 'screened-newsletters', to: 'Information/Newsletters' }, { from: 'Updates', to: 'Information/Newsletters' }, { from: 'Education', to: 'Information' }, // Move to parent since Education sub-label doesn't exist { from: 'Banking', to: 'Financial/Banking' }, { from: 'Transactions', to: 'Financial/Receipts' }, { from: 'Shopping', to: 'Commerce/Orders' }, { from: 'Technical', to: 'Professional/GitHub' }, { from: 'Unsubscribed', to: 'Archive' } ]; console.log('πŸ“§ STARTING EMAIL MIGRATIONS:'); console.log('='.repeat(60)); let totalEmailsMigrated = 0; for (const migration of migrations) { try { // Find source mailbox const sourceMailbox = mailboxes.find(mb => mb.name === migration.from); if (!sourceMailbox) { console.log(`⚠️ Source '${migration.from}' not found`); continue; } if (sourceMailbox.totalEmails === 0) { console.log(`βœ… ${migration.from} β†’ ${migration.to} (already empty)`); continue; } // Find target mailbox let targetMailbox; if (migration.to.includes('/')) { const [parentName, childName] = migration.to.split('/'); const parent = mailboxes.find(mb => mb.name === parentName); if (parent) { targetMailbox = mailboxes.find(mb => mb.parentId === parent.id && mb.name === childName ); } } else { targetMailbox = mailboxes.find(mb => mb.name === migration.to); } if (!targetMailbox) { console.log(`❌ Target '${migration.to}' not found for ${migration.from}`); continue; } console.log(`\nπŸ“§ Migrating: ${migration.from} β†’ ${migration.to}`); console.log(` πŸ“Š Emails to move: ${sourceMailbox.totalEmails}`); console.log(` 🎯 Target ID: ${targetMailbox.id}`); // Get emails using correct method signature let allEmailIds = []; let position = 0; const batchSize = 100; while (true) { console.log(` πŸ“₯ Loading emails batch at position ${position}...`); const emailResult = await client.getEmails(sourceMailbox.id, batchSize, position); if (!emailResult || !emailResult.emails || emailResult.emails.length === 0) { break; } allEmailIds.push(...emailResult.emails.map(email => email.id)); console.log(` πŸ“₯ Loaded ${emailResult.emails.length} emails (total: ${allEmailIds.length})`); if (emailResult.emails.length < batchSize) { break; // Last batch } position += batchSize; } if (allEmailIds.length > 0) { console.log(` πŸ”„ Moving ${allEmailIds.length} emails...`); // Move emails in smaller batches const moveBatchSize = 25; let moved = 0; for (let i = 0; i < allEmailIds.length; i += moveBatchSize) { const batch = allEmailIds.slice(i, i + moveBatchSize); try { await client.moveEmailsToMailbox(batch, targetMailbox.id); moved += batch.length; console.log(` βœ… Moved ${moved}/${allEmailIds.length} emails`); } catch (error) { console.log(` ⚠️ Batch error (continuing): ${error.message}`); } // Delay between batches await new Promise(resolve => setTimeout(resolve, 2000)); } totalEmailsMigrated += moved; console.log(` πŸŽ‰ Successfully migrated ${moved} emails`); } else { console.log(` ℹ️ No emails found in source mailbox`); } } catch (error) { console.log(` ❌ Migration error for ${migration.from}: ${error.message}`); } } // Handle Transactions sub-folders console.log('\nπŸ“¦ Handling Transactions sub-folders...'); const transactionsParent = mailboxes.find(mb => mb.name === 'Transactions'); if (transactionsParent) { const transactionChildren = mailboxes.filter(mb => mb.parentId === transactionsParent.id); for (const child of transactionChildren) { if (child.totalEmails > 0) { console.log(`\nπŸ“§ Moving from Transactions/${child.name} (${child.totalEmails} emails)`); const targetPath = child.name === 'Orders' ? 'Commerce/Orders' : 'Financial/Receipts'; const [parentName, childName] = targetPath.split('/'); const parent = mailboxes.find(mb => mb.name === parentName); const target = parent ? mailboxes.find(mb => mb.parentId === parent.id && mb.name === childName ) : null; if (target) { try { const emailResult = await client.getEmails(child.id, 100, 0); if (emailResult && emailResult.emails && emailResult.emails.length > 0) { const emailIds = emailResult.emails.map(e => e.id); await client.moveEmailsToMailbox(emailIds, target.id); console.log(` βœ… Moved ${emailIds.length} emails to ${targetPath}`); totalEmailsMigrated += emailIds.length; } } catch (error) { console.log(` ❌ Error moving from Transactions/${child.name}: ${error.message}`); } } } } } console.log('\nπŸŽ‰ ALL EMAIL MIGRATIONS COMPLETE!'); console.log('='.repeat(60)); console.log(`πŸ“Š Total emails migrated: ${totalEmailsMigrated}`); if (totalEmailsMigrated > 0) { console.log('βœ… Emails successfully organized in hierarchical structure'); console.log('βœ… Old folders should now be empty and ready for deletion'); } else { console.log('⚠️ No emails were migrated - check for issues'); } } catch (error) { console.log('❌ Error:', error.message); console.error(error.stack); } } migrateAllEmailsFixed().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