import win32com.client import os import pathlib # --- CONFIGURATION --- pst_path = r'd:\Dropbox\!!!Days\Downloads Z230\PST\tkulhava.pst' output_dir = r'd:\Dropbox\!!!Days\Downloads Z230\PST\pictures' # Image extensions to look for (case insensitive) IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tif', '.tiff'} def fix_encoding(text): """Repairs text wrongly decoded as cp1252 instead of cp1250.""" if not text: return "" try: return text.encode('cp1252').decode('cp1250') except Exception: return text def get_unique_filepath(directory, filename): """ Checks if a file exists. If so, adds a counter (_1, _2) to the filename until a unique name is found. """ # Clean filename of illegal characters just in case filename = "".join(x for x in filename if x.isalnum() or x in "._- ") path = pathlib.Path(directory) / filename if not path.exists(): return path # Split name and extension stem = path.stem suffix = path.suffix counter = 1 while True: new_filename = f"{stem}_{counter}{suffix}" new_path = pathlib.Path(directory) / new_filename if not new_path.exists(): return new_path counter += 1 def process_item_attachments(item, save_folder): """Checks an item for attachments and saves pictures.""" try: # Check if item has attachments if item.Attachments.Count > 0: for attachment in item.Attachments: try: # Get filename and extension fname = getattr(attachment, 'FileName', '') if not fname: continue # Fix encoding on filename if needed (sometimes attachments inherit bad encoding) fname = fix_encoding(fname) ext = os.path.splitext(fname)[1].lower() if ext in IMAGE_EXTENSIONS: # Determine unique path save_path = get_unique_filepath(save_folder, fname) # Save the file attachment.SaveAsFile(str(save_path)) print(f" [SAVED] {save_path.name}") except Exception as e: print(f" [ERROR saving attachment]: {e}") except Exception: # Some items (like corrupted notes) fail when accessing .Attachments pass def scan_folder_recursively(folder, save_folder): """Recursively walks folders and processes items.""" try: folder_name = fix_encoding(folder.Name) # Optional: Print folder progress if folder.Items.Count > 0: print(f"Scanning Folder: {folder_name}...") # Process items in this folder for item in folder.Items: process_item_attachments(item, save_folder) # Recursion for subfolder in folder.Folders: scan_folder_recursively(subfolder, save_folder) except Exception as e: print(f"Skipping folder '{fix_encoding(folder.Name)}': {e}") def main(): # 1. Ensure output directory exists if not os.path.exists(output_dir): os.makedirs(output_dir) print(f"Created directory: {output_dir}") if not os.path.exists(pst_path): print(f"Error: PST file not found at {pst_path}") return try: # 2. Connect to Outlook outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI") print(f"Mounting PST: {pst_path}...") outlook.AddStore(pst_path) # 3. Find the PST folder pst_name = "tkulhava" # Usually derived from filename root_folder = None for folder in outlook.Folders: if pst_name.lower() in folder.Name.lower(): root_folder = folder break if not root_folder: root_folder = outlook.Folders.GetLast() print(f"Opened: {fix_encoding(root_folder.Name)}") print(f"Saving pictures to: {output_dir}") print("=" * 50) # 4. Start processing scan_folder_recursively(root_folder, output_dir) # 5. Cleanup outlook.RemoveStore(root_folder) print("\nDone. PST detached.") except Exception as e: print(f"Critical Error: {e}") if __name__ == "__main__": main()