#!/usr/bin/env node
import { FastMailClient } from './src/fastmail-client.js';
import dotenv from 'dotenv';
dotenv.config({ path: '../.env' });
async function deleteExcessLabels() {
console.log('๐งน CLEANING UP EXCESS/DUPLICATE LABELS\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();
// Define the CORRECT hierarchical structure we want to keep
const correctStructure = {
'Information': ['Newsletters', 'News'],
'Financial': ['Receipts', 'Banking', 'Bills'],
'Commerce': ['Orders', 'Subscriptions'],
'Professional': ['GitHub', 'Security'],
'Personal': ['Health', 'Travel']
};
const systemFolders = ['Inbox', 'Sent', 'Drafts', 'Trash', 'Spam', 'Archive'];
console.log('๐ CURRENT FOLDER STRUCTURE:');
console.log('='.repeat(80));
const foldersToKeep = new Set();
const foldersToDelete = [];
// Add system folders to keep list
systemFolders.forEach(name => foldersToKeep.add(name));
// Add correct hierarchical structure to keep list
Object.keys(correctStructure).forEach(parent => {
foldersToKeep.add(parent);
correctStructure[parent].forEach(child => {
foldersToKeep.add(`${parent}/${child}`);
});
});
// Analyze all folders
mailboxes.forEach(mailbox => {
const isSystemFolder = systemFolders.includes(mailbox.name);
const isParentFolder = Object.keys(correctStructure).includes(mailbox.name);
let folderPath = mailbox.name;
if (mailbox.parentId) {
const parent = mailboxes.find(mb => mb.id === mailbox.parentId);
if (parent) {
folderPath = `${parent.name}/${mailbox.name}`;
}
}
const shouldKeep = foldersToKeep.has(folderPath) || foldersToKeep.has(mailbox.name);
if (shouldKeep) {
console.log(`โ
KEEP: ${folderPath} (${mailbox.totalEmails} emails)`);
} else {
console.log(`โ DELETE: ${folderPath} (${mailbox.totalEmails} emails)`);
foldersToDelete.push({
id: mailbox.id,
name: folderPath,
emailCount: mailbox.totalEmails
});
}
});
console.log('\n๐๏ธ FOLDERS MARKED FOR DELETION:');
console.log('='.repeat(60));
if (foldersToDelete.length === 0) {
console.log('โ
No excess folders found - structure is already clean!');
return;
}
let totalEmailsToMove = 0;
foldersToDelete.forEach((folder, index) => {
console.log(`${index + 1}. ${folder.name} (${folder.emailCount} emails)`);
totalEmailsToMove += folder.emailCount;
});
console.log(`\n๐ Total emails to relocate: ${totalEmailsToMove}`);
// Get Archive folder for moving emails
const archiveFolder = mailboxes.find(mb => mb.name === 'Archive');
if (!archiveFolder) {
console.log('โ Archive folder not found - cannot relocate emails');
return;
}
console.log('\n๐ RELOCATING EMAILS AND DELETING EXCESS FOLDERS:');
console.log('='.repeat(80));
let totalMoved = 0;
let totalDeleted = 0;
for (const folder of foldersToDelete) {
try {
console.log(`\n๐ Processing: ${folder.name}`);
// Move emails to Archive if folder has any
if (folder.emailCount > 0) {
console.log(` ๐ง Moving ${folder.emailCount} emails to Archive...`);
const emailResult = await client.getEmails(folder.id, folder.emailCount, 0);
if (emailResult?.emails?.length) {
const emailIds = emailResult.emails.map(e => e.id);
await client.moveEmailsToMailbox(emailIds, archiveFolder.id);
totalMoved += emailIds.length;
console.log(` โ
Moved ${emailIds.length} emails to Archive`);
}
// Small delay to prevent API overwhelming
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Delete the empty folder
console.log(` ๐๏ธ Deleting folder: ${folder.name}`);
await client.deleteMailbox(folder.id);
totalDeleted++;
console.log(` โ
Deleted successfully`);
} catch (error) {
console.log(` โ Error processing ${folder.name}: ${error.message}`);
}
}
console.log('\n๐ CLEANUP COMPLETE!');
console.log('='.repeat(60));
console.log(`๐ง Emails relocated to Archive: ${totalMoved}`);
console.log(`๐๏ธ Excess folders deleted: ${totalDeleted}/${foldersToDelete.length}`);
console.log('โ
Email organization structure is now clean and optimized!');
} catch (error) {
console.log('โ Error:', error.message);
}
}
deleteExcessLabels().catch(console.error);