# utils/attachment_handler.py import os import hashlib import re def _contenido_hash(parte): contenido = parte.get_payload(decode=True) or b"" return hashlib.md5(contenido).hexdigest() def guardar_adjunto(parte, dir_adjuntos): nombre = parte.get_filename() if not nombre: return None nombre = re.sub(r'[<>:"/\\|?*]', "_", nombre) ruta = os.path.join(dir_adjuntos, nombre) if os.path.exists(ruta): hash_nuevo = _contenido_hash(parte) with open(ruta, "rb") as f: hash_existente = hashlib.md5(f.read()).hexdigest() if hash_nuevo == hash_existente: return ruta base, ext = os.path.splitext(nombre) i = 1 while os.path.exists(ruta): ruta = os.path.join(dir_adjuntos, f"{base}_{i}{ext}") i += 1 with open(ruta, "wb") as f: f.write(parte.get_payload(decode=True)) return ruta def guardar_imagen(parte, dir_adjuntos): """ Guarda una imagen (inline o adjunta). Si no tiene filename, genera uno basado en Content-ID o hash, preservando la extensión según el subtype. Devuelve la ruta completa del archivo guardado. """ nombre = parte.get_filename() if not nombre: # Intentar usar Content-ID content_id = parte.get("Content-ID", "") or parte.get("Content-Id", "") content_id = content_id.strip("<>") if content_id else "" ext = f".{parte.get_content_subtype() or 'bin'}" base = ( re.sub(r"[^\w\-]+", "_", content_id) if content_id else _contenido_hash(parte) ) nombre = f"img_{base}{ext}" nombre = re.sub(r'[<>:"/\\|?*]', "_", nombre) ruta = os.path.join(dir_adjuntos, nombre) if os.path.exists(ruta): hash_nuevo = _contenido_hash(parte) with open(ruta, "rb") as f: hash_existente = hashlib.md5(f.read()).hexdigest() if hash_nuevo == hash_existente: return ruta base, ext = os.path.splitext(nombre) i = 1 while os.path.exists(ruta): ruta = os.path.join(dir_adjuntos, f"{base}_{i}{ext}") i += 1 with open(ruta, "wb") as f: f.write(parte.get_payload(decode=True)) return ruta