Hello there.
With the help of Chatgpt I wrote a code that saves all active Emails from Outlook to a folder with the date and subject of the Email. Working pretty good expect some fails i cant explain.
The code saves the email and the folder and then puts the Email into the folder.
And at that point in some cases appears an error that the folder/path doesnt exists, even thought it does. I thought it could be because of the path lenght exending the 260 limit but then i tried a test Email that had a way longer subject and it still worked. The code also deletes all symbols that could trigger the file name under windows. Do you have an idea what those fails are about?
Thanks!
The code:
import os
import shutil
import re
import datetime
import win32com.client
import win32timezone
import win32file # Importiere pywin32 für das Verschieben von Dateien
def clean_filename(filename):
"""Replaces invalid characters in the filename and removes duplicate spaces."""
invalid_chars = r'\\/:*?"<>|'
for char in invalid_chars:
filename = filename.replace(char, '') # Entfernt ungültige Zeichen
# Replace multiple spaces with a single space
filename = re.sub(r'\s+', ' ', filename)
filename = filename.strip() # Entfernt führende und nachfolgende Leerzeichen
if not filename:
filename = "Unbenannte_E-Mail"
return filename
def move_file_windows(source, destination):
"""Verwendet win32file.MoveFile, um die Datei ähnlich wie Drag & Drop zu verschieben."""
try:
# Windows-spezifischer Move-Versuch
win32file.MoveFile(source, destination)
print(f"E-Mail erfolgreich verschoben: {destination}")
except Exception as e:
print(f"Fehler beim Verschieben der E-Mail mit pywin32: {e}")
# Fallback auf shutil.move falls es Probleme gibt
try:
shutil.move(source, destination)
print(f"E-Mail erfolgreich verschoben mit shutil: {destination}")
except Exception as e:
print(f"Fehler beim Verschieben mit shutil: {e}")
def save_emails():
# Get the directory where the Python or EXE file is stored
script_dir = os.path.dirname(os.path.realpath(__file__))
# Define the base folder for saving emails relative to the script directory
base_path = script_dir # Use the directory where the script is located
# Check if base folder exists
if not os.path.exists(base_path):
print(f"Der Basisordner existiert nicht: {base_path}")
return
print(f"Base Path: {base_path}")
# Outlook application
outlook = win32com.client.Dispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")
active_explorer = outlook.ActiveExplorer()
selection = active_explorer.Selection
if len(selection) == 0:
print("Bitte wählen Sie mindestens eine E-Mail aus.")
return
# Sort emails by received time (ascending order, older emails first)
emails = sorted(selection, key=lambda item: item.ReceivedTime)
# Dictionary to track duplicates (key: date + subject, value: list of emails)
email_groups = {}
# Group emails by date and subject
for item in emails:
if item.Class == 43: # Check if item is a MailItem
subject = clean_filename(item.Subject)
received_date = item.ReceivedTime
date_str = received_date.strftime('%Y.%m.%d')
folder_key = f"{date_str}_{subject}"
if folder_key not in email_groups:
email_groups[folder_key] = []
email_groups[folder_key].append(item)
# Process grouped emails
for folder_key, items in email_groups.items():
date_str, subject = folder_key.split("_", 1)
for idx, item in enumerate(items):
# Determine folder and file names
if len(items) > 1: # Add counter if there are duplicates
counter = idx + 1
folder_name = f"{date_str}_{counter}_{subject}"
file_name = f"{counter}_{subject}.msg"
else: # No counter if only one email with this subject and date
folder_name = f"{date_str}_{subject}"
file_name = f"{subject}.msg"
folder_name = folder_name.strip()
final_folder_path = os.path.join(base_path, folder_name)
# Check if folder exists, otherwise create it
try:
os.makedirs(final_folder_path, exist_ok=True) # Ensure folder exists
print(f"Ordner erstellt: {final_folder_path}")
except Exception as e:
print(f"Fehler beim Erstellen des Ordners: {e}")
continue
temp_file_path = os.path.join(base_path, file_name)
final_file_path = os.path.join(final_folder_path, file_name)
# Save email
try:
item.SaveAs(temp_file_path, 3) # 3 corresponds to olMsg format
print(f"Email gespeichert: {temp_file_path}")
except Exception as e:
print(f"Fehler beim Speichern der E-Mail: {e}")
continue
# Move the file to the new folder using pywin32
move_file_windows(temp_file_path, final_file_path)
if __name__ == "__main__":
save_emails()
input("Drücken Sie die Eingabetaste, um das Fenster zu schließen/Premere il tasto Invio per chiudere la finestra...")
Thanks. Will try it. But dont think that makes the problems I`m facing. Cause just cant seem to find the difference between the 100 Emails that are working and those three to four that arent
Can you please provide the traceback error that is generated.
What is fundamentally different from the ones that are passing from those that are failing? Are there some “invalid” characters in the folder path that perhaps you have not considered from your list above?
Sry for having it only as pictures but a coworker run into those problems.
And the thing is those Emails that cuase problems arent different from others. There are others with the same special caracters and also other with longer names. Also tried to send myself some Emails with even longer subjects and even more special caracters but it always worked flawless. Note that my coworker has windows 11 and i have windows 10 but I dont think that that makes a difference at all. I mean i just cant figure out what those Emails that dont work make different than those who work
Which Python version are you using? If you’re using a much older version, can you upgrade to the latest version?
Note that for the “WinError 3” which you are observing has to do with a potentially invalid file path or you may not have permission to access those directories (i.e., paths).
Reference the following link and insight into the potential workaround:
I do use 3.13.1 on my and also on my coworkes computer
Also tried to provocate the errror by sending the same Emails that caused the error to myself but then everything is just fine
Yeah thought the WinError 3 would come from the python trying to move the Email into the right folder but somehow even when the exact path exists it doesnt work. Path cant be to long cause for other ever longer paths it does work. And also cant be something with the permission cause for the other Emails in the same folder it does work.
I also thought about some code that only does its thing when this error appears some sort like telling it to move the mail into the nearest location that corresponds to the name but im not sure if that causes even more caos
Make sure that the folder is being created prior to attempting to save the email into it. If not, then the path will not be valid since it does not yet exist.
Yes the logic involves creating all subfolders and saving the emails to the main folder and than trying to transfer the emails to the subfolders. Did that so the emails that make errors stay at the main folder so you can locate errors faster.
Now i implementet this piece:
# Zusätzliche Logik: Passenden Ordner suchen
print("Suche nach einem passenden Ordner...")
date_str = email_date.strftime('%Y.%m.%d') # Datum im Ordnerformat
email_subject = clean_filename(email_subject) # Betreff bereinigen
for root, dirs, files in os.walk(base_path):
for dir_name in dirs:
# Prüfen, ob Ordnername mit Datum und Betreff übereinstimmt
if dir_name.startswith(date_str) and email_subject in dir_name:
potential_folder = os.path.join(root, dir_name)
potential_destination = os.path.join(potential_folder, os.path.basename(source))
# Prüfen, ob die Datei bereits existiert
if os.path.exists(potential_destination):
print(f"Datei existiert bereits in: {potential_destination}, wird übersprungen.")
return
# Verschieben in passenden Ordner
try:
shutil.move(source, potential_destination)
print(f"E-Mail erfolgreich in passenden Ordner verschoben: {potential_destination}")
return
except Exception as e:
print(f"Fehler beim Verschieben in passenden Ordner: {e}")
# Falls kein passender Ordner gefunden wurde
print(f"Kein passender Ordner für die E-Mail gefunden. Datei bleibt in {source}.")
that in theorie should try to move the Mails that stayed in the main folder into the subfolders by comparing their names and maybe finding one that works. Will let my coworker try this to see if it works.
Thank you so so much for your help till now really appreciate it!
Hello so tried it now. Does work in 99 from 100 cases but theres always that one case that doesnt work and I cant seem to figure out why. It makes the subfolder for the Email then it saves the Email in the folder above and tries to drag it into the subfolder, thats where the subfolder cant be found even tho the path matches the exact path that was created in that second. Then it tries with an other method and finally it tries to find the subfolder with even an other method. All errors
Can you see a reason? Cant be anywhing about write abbilities cause in the othe 99 cases it works. Also cant be because of the path lenght cause there are longer paths and same for special caracters there a other emails with the same special caracters that work.
Heres the error log:
Created the folder: C:\Users\user24\Downloads\_smistamento_MAIL\2023.10.05_Fw Bau der Nordwestumfahrung Meran 2. Baulos Baumeisterarbeiten 12. Baufortschritt bis einschließlich 30.09.2023
Saved the Email: C:\Users\user24\Downloads\_smistamento_MAIL\Fw Bau der Nordwestumfahrung Meran 2. Baulos Baumeisterarbeiten 12. Baufortschritt bis einschließlich 30.09.2023.msg
Error when moving the email with pywin32: (3, 'MoveFile', 'Unable to find the specified path.')
Error when moving with shutil: [WinError 3] Unable to find the specified path.
Searching for a matching folder... Error when moving to the matching folder: [WinError 3] Unable to find the specified path.
No matching folder found: Email stays in this path: C:\Users\user24\Downloads\_smistamento_MAIL Fw Bau der No rdwestumfahrung Meran 2. Baulos Baumeisterarbeiten 12. Baufortschritt bis einschließlich 30.09.2023.msg.
When creating your filenames, please ensure that you are following Python naming conventions:
No empty spaces (avoid trailing spaces)
Replace empty spaces with underscores (‘_’)
Replace ‘.’ periods with underscores (‘_’)
From:
As a first general rule, you shouldn’t leave spaces between words in the name of a file or object.
Different pieces of software may treat empty space in different ways, and sometimes they might even be unable to do so. Remember – don’t use whitespaces when naming files or programming entities.
Review your file names and ensure that at a minimum these conventions are being followed.
I don’t know. But what we can do is start by following recommended file naming conventions. If we start deviating from the recommended naming conventions, then we shouldn’t be surprised if we start running into issues.