import win32com.client import os import hashlib from datetime import datetime, timedelta from tqdm import tqdm import time import locale # Imposta la localizzazione in italiano try: locale.setlocale(locale.LC_TIME, "it_IT.UTF-8") # Per Windows/Linux moderni except: # noqa: E722 try: locale.setlocale(locale.LC_TIME, "ita_ita") # Specifica per Windows except: # noqa: E722 print("Impossibile impostare il locale italiano, uso i nomi manuali.") # --- CONFIGURAZIONE --- ARCHIVE_NAME = "Archivio online - alessandro.battilani@intesasanpaolo.com" ONEDRIVE_PATH = r"C:\Users\U086304\OneDrive - Intesa SanPaolo\Allegati_Outlook" if not os.path.exists(ONEDRIVE_PATH): os.makedirs(ONEDRIVE_PATH) print(f"Cartella creata: {ONEDRIVE_PATH}") MONTHS_LIMIT = 5 # ---------------------- def get_file_hash(file_path): hasher = hashlib.md5() with open(file_path, 'rb') as f: for chunk in iter(lambda: f.read(4096), b""): hasher.update(chunk) return hasher.hexdigest() def main(): if not os.path.exists(ONEDRIVE_PATH): os.makedirs(ONEDRIVE_PATH) print("Connessione a Outlook in corso...") try: outlook = win32com.client.Dispatch("Outlook.Application") namespace = outlook.GetNamespace("MAPI") inbox = namespace.GetDefaultFolder(6) archive_root = namespace.Folders.Item(ARCHIVE_NAME) except Exception as e: print(f"Errore di connessione: {e}") return cutoff_date = datetime.now() - timedelta(days=MONTHS_LIMIT * 30) filter_date_str = cutoff_date.strftime("%d/%m/%Y %H:%M") filter_str = f"[ReceivedTime] < '{filter_date_str}'" items = inbox.Items.Restrict(filter_str) items.Sort("[ReceivedTime]", True) total_items = items.Count if total_items == 0: print("Nessuna email da archiviare.") return print(f"Trovate {total_items} email vecchie. Inizio archiviazione...") processed_files = {} archived_count = 0 mesi_it = {1: "Gennaio", 2: "Febbraio", 3: "Marzo", 4: "Aprile", 5: "Maggio", 6: "Giugno", 7: "Luglio", 8: "Agosto", 9: "Settembre", 10: "Ottobre", 11: "Novembre", 12: "Dicembre"} with tqdm(total=total_items, desc="Archiviazione", unit="mail", colour='green') as pbar: for i in range(total_items, 0, -1): try: item = items.Item(i) pbar.update(1) if not hasattr(item, 'ReceivedTime'): continue rt = item.ReceivedTime received_time = datetime(rt.year, rt.month, rt.day, rt.hour, rt.minute) anno_str = str(received_time.year) nome_mese = mesi_it[received_time.month] pbar.set_description(f"Mese: {nome_mese} {anno_str}") # Cartelle month_folder_name = f"{received_time.month:02d}-{nome_mese}" try: y_f = archive_root.Folders.Item(anno_str) except: # noqa: E722 y_f = archive_root.Folders.Add(anno_str) try: target_folder = y_f.Folders.Item(month_folder_name) except: # noqa: E722 target_folder = y_f.Folders.Add(month_folder_name) # --- TENTA LO SPOSTAMENTO CON RETRY --- archived_item = None for tentativo in range(3): try: archived_item = item.Move(target_folder) if archived_item: archived_item.Save() time.sleep(0.5) # Pausa vitale per il server break except: # noqa: E722 time.sleep(1) # Aspetta se il server è occupato if not archived_item: pbar.set_postfix(error="Move fallito") continue # --- GESTIONE ALLEGATI (SOLO FILE VERI) --- if archived_item.Class == 43 and archived_item.Attachments.Count > 0: has_changed = False attachments = [archived_item.Attachments.Item(j) for j in range(1, archived_item.Attachments.Count + 1)] for att in attachments: try: # 1. Filtro base: solo allegati di tipo "Valore" (file) if att.Type != 1: continue # 2. FILTRO AVANZATO: Salta le immagini nelle firme (Inline Images) # Controlliamo se l'allegato ha un "Content-ID" (tipico delle immagini incorporate) try: prop_accessor = att.PropertyAccessor cid = prop_accessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E") if cid: # Se ha un CID, è un'immagine nel testo/firma continue except: # Se non riesce a leggere la proprietà, procediamo con cautela # (spesso i file veri non hanno questa proprietà) pass # 3. FILTRO ESTENSIONI: Opzionale, se vuoi escludere png/jpg a prescindere # ext = os.path.splitext(att.FileName)[1].lower() # if ext in ['.png', '.jpg', '.jpeg', '.gif']: continue # --- Procedura di salvataggio con DATA nel nome --- temp_path = os.path.join(os.environ['TEMP'], att.FileName) att.SaveAsFile(temp_path) f_hash = get_file_hash(temp_path) # Creiamo il prefisso con la data (es. 2025-02-09_) date_prefix = received_time.strftime("%Y-%m-%d") if f_hash not in processed_files: # Il nome file sarà: DATA_HASH_NOMEORIGINALE.ext # Usiamo l'hash corto (primi 6 caratteri) per non avere nomi infiniti unique_name = f"{date_prefix}_{f_hash[:6]}_{att.FileName}" dest_path = os.path.join(ONEDRIVE_PATH, unique_name) if not os.path.exists(dest_path): os.replace(temp_path, dest_path) processed_files[f_hash] = dest_path else: dest_path = processed_files[f_hash] os.remove(temp_path) # Il link nella mail punterà al nuovo nome con la data link_html = ( f"