From d7f4a7848d413e34244fa4b050ad23a77f7999e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Koco=C5=84?= <39369166+jkocon@users.noreply.github.com> Date: Wed, 26 Feb 2025 20:30:19 +0100 Subject: [PATCH] Update archive_emails.py --- src/archive_emails.py | 82 +++++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/src/archive_emails.py b/src/archive_emails.py index b9d1209..01977b0 100644 --- a/src/archive_emails.py +++ b/src/archive_emails.py @@ -2,7 +2,6 @@ import win32com.client import sys import datetime - def list_outlook_mailboxes(): """Returns a list of available mailboxes in Outlook.""" outlook = win32com.client.Dispatch("Outlook.Application") @@ -34,9 +33,10 @@ def list_main_folders(mailbox_name): return [folder.Name for folder in mailbox.Folders] def main_archive(): + """Main function to select a mailbox and folders for archiving.""" total_emails_moved = 0 total_size_moved_kb = 0 - """Main function to select a mailbox and folders for archiving.""" + mailboxes = list_outlook_mailboxes() if not mailboxes: print("No mailboxes found in Outlook.") @@ -61,7 +61,6 @@ def main_archive(): print("No corresponding Online Archive found. Exiting.") sys.exit(1) - # ✅ Sprawdźmy, czy wybrana skrzynka jest poprawna print(f"Selected mailbox: {mailbox_name}") main_folders = list_main_folders(mailbox_name) @@ -86,67 +85,96 @@ def main_archive(): outlook = win32com.client.Dispatch("Outlook.Application") namespace = outlook.GetNamespace("MAPI") + + # Referencja do wybranego mailboxa i archiwum mailbox = namespace.Folders[mailbox_name] + archive_root = namespace.Folders[archive_mailbox] for folder_name in selected_folder_names: try: print(f"Accessing folder: {folder_name}") folder = mailbox.Folders[folder_name] - try: - archive_folder = namespace.Folders[archive_mailbox].Folders[folder_name] - except Exception: - print(f"Archive folder '{folder_name}' does not exist. Attempting to create it...") - try: - archive_folder = namespace.Folders[archive_mailbox].Folders.Add(folder_name) - except Exception as e: - print(f"Failed to create archive folder '{folder_name}'. Skipping. Error: {e}") - continue + # [ZMIANA] - Tworzymy (lub pobieramy) identyczny folder w archiwum + archive_folder = get_or_create_subfolder(archive_root, folder_name) emails_moved, size_moved_kb = process_folder(folder, archive_folder, run_type) total_emails_moved += emails_moved total_size_moved_kb += size_moved_kb + except Exception as e: - print(f"Error accessing folder {folder_name}: {e}") + print(f"Error accessing folder {folder_name}: {e}") print("Dry-run complete. No emails were moved." if run_type == 'dry-run' else "Email move completed.") print(f"Total emails processed: {total_emails_moved}") print(f"Total size processed: {total_size_moved_kb / 1024:.2f} MB") + except (ValueError, IndexError): print("Invalid folder selection.") sys.exit(1) +def get_or_create_subfolder(parent_folder, subfolder_name): + """ + Sprawdza, czy w folderze 'parent_folder' istnieje podfolder 'subfolder_name'. + Jeśli nie istnieje — tworzy go. Zwraca referencję do podfolderu. + """ + try: + return parent_folder.Folders[subfolder_name] + except: + print(f"Archive folder '{subfolder_name}' does not exist in '{parent_folder.Name}'. Attempting to create it...") + try: + new_folder = parent_folder.Folders.Add(subfolder_name) + return new_folder + except Exception as e: + print(f"Failed to create subfolder '{subfolder_name}' in '{parent_folder.Name}'. Error: {e}") + # Jeśli nie możemy utworzyć podfolderu, zwracamy sam parent_folder, + # ale w praktyce powinniśmy przerywać, bo maile nie trafią tam, gdzie chcemy. + return parent_folder + def process_folder(folder, archive_folder, run_type, depth=0): - old_email_count = 0 - total_size_kb = 0 - """Processes a folder and its subfolders, counting and optionally moving emails.""" + """ + Processes a folder and its subfolders, moving or counting old emails. + Zwraca liczbę przeniesionych maili i sumaryczny rozmiar w KB. + """ old_email_count = 0 total_size_kb = 0 try: - # print(f"{' ' * depth}Processing folder: {folder.Name}") + #print(f"{' ' * depth}Processing folder: {folder.Name}") + # Dla debugowania, możemy podejrzeć obie ścieżki: + #print(f"{' ' * depth}Source folder path: {folder.FolderPath}") + #print(f"{' ' * depth}Archive folder path: {archive_folder.FolderPath}") + for item in folder.Items: + # Sprawdzamy np. 12 miesięcy wstecz if hasattr(item, 'ReceivedTime') and item.ReceivedTime < (datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=365)): old_email_count += 1 total_size_kb += item.Size / 1024 + #print(item.Subject) if run_type == 'move': - item.Move(archive_folder) + try: + item.Move(archive_folder) + except Exception as move_err: + print(f"Error moving item: {move_err}") + print(f"{' ' * depth}Source folder path: {folder.FolderPath}") + print(f"{' ' * depth}Archive folder path: {archive_folder.FolderPath}") + + if old_email_count > 0: + status_text = "would be moved" if run_type == "dry-run" else "moved" + print(f"{' ' * depth}Folder '{folder.Name}': {old_email_count} emails " + f"({total_size_kb / 1024:.2f} MB) {status_text}.") + except Exception as e: print(f"Error processing folder {folder.Name}: {e}") - # ✅ PRZENIESIONE POZA EXCEPT → teraz zawsze przetwarza podfoldery - if old_email_count > 0 : - print(f"{' ' * depth}Folder '{folder.Name}': {old_email_count} emails ({total_size_kb / 1024:.2f} MB) would be moved.") - + # [ZMIANA] Dla każdego podfolderu w skrzynce źródłowej odtwarzamy podfolder w archiwum for subfolder in folder.Folders: - sub_emails, sub_size = process_folder(subfolder, archive_folder, run_type, depth + 1) + sub_archive_folder = get_or_create_subfolder(archive_folder, subfolder.Name) + sub_emails, sub_size = process_folder(subfolder, sub_archive_folder, run_type, depth + 1) old_email_count += sub_emails total_size_kb += sub_size + return old_email_count, total_size_kb - process_folder(subfolder, archive_folder, run_type, depth + 1) - - - if __name__ == "__main__": main_archive()