Shrink an IMAP mailbox by moving large attachments out of old emails and onto local disk.
The script walks every folder of an IMAP account, finds large, old messages, saves their attachments locally, and replaces each original with a lightweight copy that keeps the subject, recipients, date and body, plus a note listing the attachments that were moved out.
For each mailbox (including nested folders):
- Search for messages larger than 10 MB received before 1 Feb 2023.
- Parse each match with postal-mime.
- Save to
./<imap-user>/<mailbox>/:<uid>.txt– the plain-text body<YYYY-MM-DD>_<uid>_<index>_<filename>– every attachment
- Append a replacement message to the same mailbox with the original date, marked as read. Its body is the original HTML/text (or a placeholder if it exceeds 1 MB), followed by the list of moved files.
- Delete the originals and expunge the mailbox.
Warning
This permanently deletes the original messages from the server. The replacement does not keep the From/Cc headers or the raw MIME structure. Run it against a backup or a test account first, and check the saved files before trusting it with real mail.
Requires Bun.
bun install
bun utf7-patch.js # patches the utf7 dependency so imap works under BunCreate config.ts in the project root (it's git-ignored). It is passed directly to imap-simple's connect():
export const config = {
imap: {
user: "you@example.com",
password: "app-password",
host: "imap.example.com",
port: 993,
tls: true,
authTimeout: 10_000,
},
};bun index.tsThe script logs each mailbox, the matching messages and every saved file, then exits once all folders are processed.
The size and date thresholds are hard-coded in handleMailbox in index.ts:
const searchCriteria = [
["LARGER", 10_000_000], // bytes
["BEFORE", new Date(2023, 1, 1)], // month is 0-based → 1 Feb 2023
];Adjust them to suit your mailbox.