import imaplib import email from email.header import decode_header from email.utils import parsedate_to_datetime import os import re from getpass import getpass from tqdm import tqdm # ๐Ÿงผ Clean up filenames def sanitize_filename(s): s = re.sub(r'[\r\n\t]', '', s) s = s.strip() s = re.sub(r'[\\/*?:"<>|]', "_", s) return s # ๐Ÿง  Interactive input print("๐Ÿ“ง Email Export Tool") EMAIL = input("Email address: ").strip() PASSWORD = getpass("Password: ") IMAP_SERVER = input("IMAP server (e.g. imap.example.com): ").strip() IMAP_PORT = int(input("IMAP port (e.g. 993): ").strip()) IMAP_FOLDER = input("IMAP folder (e.g. INBOX): ").strip() or "INBOX" OUTPUT_DIR = input("Output directory (e.g. email_export): ").strip() or "email_export" # ๐Ÿ“ฆ Create output directories os.makedirs(OUTPUT_DIR, exist_ok=True) attachments_dir = os.path.join(OUTPUT_DIR, "attachments") os.makedirs(attachments_dir, exist_ok=True) # ๐Ÿ”Œ Connect to server try: mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT) mail.login(EMAIL, PASSWORD) mail.select(IMAP_FOLDER) print("โœ… Connected successfully.") except Exception as e: print(f"โŒ Connection failed: {e}") exit() # ๐Ÿ“ฅ Search for all emails status, messages = mail.search(None, "ALL") email_ids = messages[0].split() exported_emails = 0 exported_attachments = 0 print(f"๐Ÿ“ฌ Found {len(email_ids)} emails. Starting export...\n") # ๐Ÿงฎ Progress bar for i in tqdm(email_ids, desc="Exporting emails", unit="email"): res, msg_data = mail.fetch(i, "(RFC822)") raw_email = msg_data[0][1] msg = email.message_from_bytes(raw_email) subject = decode_header(msg["Subject"] or "no_subject")[0][0] if isinstance(subject, bytes): subject = subject.decode(errors="ignore") subject = sanitize_filename(subject or "no_subject") from_ = msg.get("From", "unknown") to = msg.get("To", "unknown") date = msg.get("Date", "") try: date_obj = parsedate_to_datetime(date) date_fmt = date_obj.strftime("%Y-%m-%d_%H-%M-%S") except: date_fmt = "unknown_date" markdown = f"---\nfrom: {from_}\nto: {to}\ndate: {date_fmt}\nsubject: {subject}\nattachments:\n" body = "" attachment_paths = [] for part in msg.walk(): content_type = part.get_content_type() filename = part.get_filename() if filename: filename = sanitize_filename(filename) filepath = os.path.join(attachments_dir, filename) try: with open(filepath, "wb") as f: f.write(part.get_payload(decode=True)) attachment_paths.append(f"[{filename}](attachments/{filename})") exported_attachments += 1 except Exception as e: print(f"โš ๏ธ Failed to save attachment: {filename} โ†’ {e}") elif content_type == "text/plain": payload = part.get_payload(decode=True) if payload: body += payload.decode(errors="ignore") if not attachment_paths: markdown += " - None\n" else: for link in attachment_paths: markdown += f" - {link}\n" markdown += "---\n\n" markdown += body.strip() filename_md = f"{date_fmt}_{subject[:50]}.md" filepath_md = os.path.join(OUTPUT_DIR, sanitize_filename(filename_md)) with open(filepath_md, "w", encoding="utf-8") as f: f.write(markdown) exported_emails += 1 # โœ… Summary print("\n๐ŸŽ‰ Export complete!") print(f"๐Ÿ“„ Emails exported: {exported_emails}") print(f"๐Ÿ“Ž Attachments saved: {exported_attachments}")