Initial commit

Claude has done a lot of work, but there are still some errors which
cause the mails to be distributed to wrong mail boxes. I am now going to
let codex and claude compete. They will have their own branches and
merge to main as soon as we are somewhere where we can switch AI.
This commit is contained in:
2026-07-04 11:18:05 +02:00
commit 4780c18d70
27 changed files with 43087 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""
Download alle e-mails van een IMAP-account naar lokale .eml-bestanden.
Gebruik: python download_mailbox.py
Resultaat: mailbox/<mapnaam>/<id>.eml
Het script is herstart-safe: al gedownloade mails worden overgeslagen.
"""
import imaplib
import os
import re
import sys
import getpass
from pathlib import Path
IMAP_HOST = "australius.nl"
IMAP_PORT = 993
LOCAL_DIR = Path(__file__).parent / "mailbox"
def parse_folder_name(line: bytes) -> str | None:
"""Haal mapnaam op uit IMAP LIST-response."""
decoded = line.decode("utf-8", errors="replace")
# Formaat: (\Flags) "delimiter" "naam" of (\Flags) "delimiter" naam
match = re.match(r'\(.*?\)\s+".*?"\s+(.*)', decoded)
if not match:
return None
name = match.group(1).strip().strip('"')
return name if name else None
def safe_path(name: str) -> str:
"""Zet mapnaam om naar een veilige directorynaam."""
return re.sub(r'[<>:"/\\|?*\x00-\x1f]', "_", name)
def download():
username = input("E-mailadres: ").strip()
password = getpass.getpass("Wachtwoord: ")
print(f"\nVerbinden met {IMAP_HOST}:{IMAP_PORT} ...")
try:
mail = imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT)
mail.login(username, password)
except Exception as exc:
print(f"Mislukt: {exc}")
sys.exit(1)
print("Ingelogd.\n")
# Alle mappen ophalen
status, raw_folders = mail.list()
if status != "OK":
print("Kan mappenlijst niet ophalen.")
sys.exit(1)
folders = [parse_folder_name(f) for f in raw_folders if f]
folders = [f for f in folders if f]
print(f"Gevonden mappen ({len(folders)}):")
for f in folders:
print(f" {f}")
print()
total_new = total_skip = total_err = 0
num_folders = len(folders)
for folder_idx, folder in enumerate(folders, 1):
folder_prefix = f"[map {folder_idx}/{num_folders}] {folder}"
quoted = f'"{folder}"'
status, data = mail.select(quoted, readonly=True)
if status != "OK":
print(f"{folder_prefix}: kan niet openen overgeslagen.")
continue
num = int(data[0])
local_dir = LOCAL_DIR / safe_path(folder)
local_dir.mkdir(parents=True, exist_ok=True)
if num == 0:
print(f"{folder_prefix}: leeg.")
continue
status, data = mail.search(None, "ALL")
if status != "OK":
print(f"{folder_prefix}: zoeken mislukt overgeslagen.")
continue
ids = data[0].split()
num_to_fetch = sum(1 for uid in ids if not (local_dir / f"{uid.decode()}.eml").exists())
new = skip = err = 0
for msg_idx, uid in enumerate(ids, 1):
path = local_dir / f"{uid.decode()}.eml"
if path.exists():
skip += 1
continue
done = new + err + 1
print(f"\r{folder_prefix}: bericht {done}/{num_to_fetch} ", end="", flush=True)
try:
status, msg_data = mail.fetch(uid, "(RFC822)")
if status == "OK" and msg_data and msg_data[0]:
path.write_bytes(msg_data[0][1])
new += 1
else:
err += 1
except Exception:
err += 1
total_new += new
total_skip += skip
total_err += err
parts = [f"{new} nieuw", f"{skip} al aanwezig"]
if err:
parts.append(f"{err} fout")
print(f"\r{folder_prefix}: " + ", ".join(parts) + " ")
mail.logout()
print(f"\nKlaar. {total_new} gedownload, {total_skip} overgeslagen", end="")
if total_err:
print(f", {total_err} fouten", end="")
print(f".\nOpgeslagen in: {LOCAL_DIR.resolve()}")
if __name__ == "__main__":
LOCAL_DIR.mkdir(exist_ok=True)
download()