commit 97eca4ff44ff5602d728b2f37683b5a76eb0ac82 Author: Artur Meski Date: Wed Apr 1 21:30:48 2026 +0100 the beginning of the end diff --git a/README.md b/README.md new file mode 100644 index 0000000..ec67b8c --- /dev/null +++ b/README.md @@ -0,0 +1,125 @@ +``` + ___ __ __ _ ____ + |_ _| \/ | /_\ | _ \ + | || \ / | /\_\\| |_) | + | || |\/| |/ ___ \ __/ + |___|_| |_/_/ \_\_| + + _ _ _ _ _ _____ + | \ | | | | | |/ / __| + | \| | | | | ' /| _| + | |\ | |_| | . \| |__ + |_| \_|\___/|_|\_\____| + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | a t o o l f o r d i g i t a l a r s o n | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +/////////////////////////////////////////////////////////////////////////////// +// // +// imap-nuke release: 2026 // +// "scorched earth for your inbox" // +// // +// brought to you by someone who finally got tired of 47,821 unread emails // +// // +/////////////////////////////////////////////////////////////////////////////// + + +-[ WTF IS THIS ]---------------------------------------------------------------- + +You have n emails. You want 0 emails. Not zero after unsubscribing from +every mailing list like some kind of COWARD. Zero. NULL. The void. + +imap-nuke connects to your Gmail over IMAP/TLS and deletes every single +message in every single folder until there is nothing left. No filter. No +mercy. No "are you sure you want to delete this memory from 2009?" - well, +one confirmation prompt, but that's it, and you have to type it in ALL CAPS +like you mean it. + + +-[ HOW IT WORKS ]--------------------------------------------------------------- + + [your gmail] [imap-nuke] [google's servers] + | | | + | u type ur password | | + |<----------------------------| | + | |--- TLS connect ---------->| + | |--- LOGIN ---------------->| + | |<-- OK yeah whatever ------| + | |--- LIST "" * ------------>| + | |<-- here's 40 folders -----| + | "type NUKE to confirm" | | + |<----------------------------| | + |--- "NUKE" ----------------->| | + | |--- SELECT [folder] ------>| + | |--- STORE +FLAGS \Deleted->| + | |--- EXPUNGE -------------->| + | | (repeat for all folders) | + | | | + | nothing nothing + +-[ USAGE ]---------------------------------------------------------------------- + +$ python3 nuke.py + +============================================================ + imap-nuke - Gmail account wiper +============================================================ + +Gmail address: doomed@gmail.com +Password (or App Password): **************** + +Connecting to imap.gmail.com... +Logged in successfully. + +Found 12 folder(s): + INBOX + [Gmail]/Sent Mail + [Gmail]/Drafts + [Gmail]/Spam + [Gmail]/Trash + [Gmail]/All Mail + ... and more + +WARNING: This will PERMANENTLY delete every message in every folder. +Account : doomed@gmail.com + +Type "NUKE" to confirm, anything else to abort: NUKE + +Nuking 'INBOX'... 12847 message(s) deleted. +Nuking '[Gmail]/Sent Mail'... 3291 message(s) deleted. +Nuking '[Gmail]/Drafts'... 17 message(s) deleted. +Nuking '[Gmail]/Spam'... 4012 message(s) deleted. +Nuking '[Gmail]/Trash'... 839 message(s) deleted. +Nuking '[Gmail]/All Mail'... 0 message(s) deleted. + +Done. 21006 message(s) deleted across 12 folder(s). + +[Gmail]/All Mail is always processed LAST. Gmail is sneaky about restoring +messages via All Mail if you nuke it first. We outsmart it. + + +-[ WARNINGS ]------------------------------------------------------------------- + + /!\ THIS IS IRREVERSIBLE /!\ + + There is no undo. There is no "recently deleted" after expunge. + Google may retain copies on their end for some period - that's + between you and Google. From YOUR account's perspective: gone. + + Do not run this on an account you want to keep. + Do not run this on someone else's account. + Do not come crying. + +-=[ EOF ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + "delete it before they screenshot it" + + imap-nuke is free software. use it, fork it, don't blame anyone. + no warranty. no support. no prisoners. + + the inbox is a lie + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +``` diff --git a/nuke.py b/nuke.py new file mode 100755 index 0000000..66da24d --- /dev/null +++ b/nuke.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +""" +imap-nuke: Permanently delete every message in a Gmail account via IMAP. + +Prerequisites: + - IMAP must be enabled in Gmail settings (Settings -> See all settings -> Forwarding and POP/IMAP) + - If your account uses 2-Step Verification, generate an App Password: + Google Account -> Security -> 2-Step Verification -> App passwords + Use that 16-character password instead of your real password. +""" + +import imaplib +import sys +import getpass +import socket + +IMAP_HOST = "imap.gmail.com" +IMAP_PORT = 993 +BATCH_SIZE = 500 + + +def connect(email: str, password: str) -> imaplib.IMAP4_SSL: + print(f"Connecting to {IMAP_HOST}...") + try: + conn = imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT) + except (socket.gaierror, OSError) as e: + sys.exit(f"Connection failed: {e}") + + try: + conn.login(email, password) + except imaplib.IMAP4.error as e: + sys.exit(f"Login failed: {e}") + + print("Logged in successfully.") + return conn + + +def list_folders(conn: imaplib.IMAP4_SSL) -> list[str]: + status, data = conn.list() + if status != "OK": + sys.exit("Failed to list folders.") + + folders = [] + for item in data: + if item is None: + continue + # IMAP LIST response: (\Flags) "delimiter" "name" or (\Flags) "delimiter" name + decoded = (item.decode() if isinstance(item, bytes) else item).strip() + if decoded.endswith('"'): + # Quoted name: extract between the last two double-quotes + name = decoded.rsplit('"', 2)[-2] + else: + # Unquoted name: last whitespace-separated token + name = decoded.rsplit(None, 1)[-1] + if name: + folders.append(name) + + return folders + + +def nuke_folder(conn: imaplib.IMAP4_SSL, folder: str) -> int: + """Mark all messages in a folder as deleted and expunge. Returns count deleted.""" + status, _ = conn.select(f'"{folder}"', readonly=False) + if status != "OK": + print(f" Skipping {folder!r} (could not select)") + return 0 + + # Search for all messages + status, data = conn.search(None, "ALL") + if status != "OK" or not data or not data[0]: + return 0 + + msg_ids = data[0].split() + if not msg_ids: + return 0 + + count = len(msg_ids) + print(f"\n {count} message(s) found.", flush=True) + # Mark and expunge in batches to avoid server timeouts on large folders + deleted = 0 + for i in range(0, len(msg_ids), BATCH_SIZE): + batch = msg_ids[i:i + BATCH_SIZE] + id_range = b",".join(batch) + conn.store(id_range, "+FLAGS", "\\Deleted") + conn.expunge() + deleted += len(batch) + print(f" {deleted}/{count} deleted...", flush=True) + return count + + +def main() -> None: + print("=" * 60) + print(" imap-nuke - Gmail account wiper") + print("=" * 60) + print() + + email = input("Gmail address: ").strip() + if not email: + sys.exit("No email provided.") + + password = getpass.getpass("Password (or App Password): ") + if not password: + sys.exit("No password provided.") + + conn = connect(email, password) + + folders = list_folders(conn) + print(f"\nFound {len(folders)} folder(s):") + for f in folders: + print(f" {f}") + + print() + print("WARNING: This will PERMANENTLY delete every message in every folder.") + print(f"Account : {email}") + confirm = input('\nType "NUKE" to confirm, anything else to abort: ').strip() + if confirm != "NUKE": + print("Aborted.") + conn.logout() + sys.exit(0) + + print() + total_deleted = 0 + + # Process [Gmail]/All Mail last - deleting from individual labels first + # avoids Gmail re-creating messages from All Mail. + priority_last = {"[Gmail]/All Mail", "[Google Mail]/All Mail"} + ordered = [f for f in folders if f not in priority_last] + \ + [f for f in folders if f in priority_last] + + for folder in ordered: + print(f"Nuking {folder!r}...", end="", flush=True) + try: + count = nuke_folder(conn, folder) + except imaplib.IMAP4.abort as e: + print(f"\n Connection dropped ({e}), reconnecting...") + conn = connect(email, password) + count = nuke_folder(conn, folder) + total_deleted += count + print(f" Done ({count} message(s) deleted).") + + print() + print(f"Done. {total_deleted} message(s) deleted across {len(folders)} folder(s).") + conn.logout() + + +if __name__ == "__main__": + main()