Asked
Updated
Viewed
67 times

I’m looking for a practical way to convert multiple MBOX files into Outlook PST format without having to process each mailbox manually. The main things I’d want to retain are the folder structure, attachments, email formatting, and other message details.

I came across a MBOX to PST Converter, which supports batch conversion and allows you to process multiple MBOX files together. It also maintains the folder hierarchy and attachments in the resulting PST.

Has anyone here used a MBOX to PST converter for a large mailbox archive? I’d be interested to know how well the folder structure and attachments are preserved after importing the PST into Outlook.

add a comment
0

1 Answer

  • Votes
  • Oldest
  • Latest
Answered

The most reliable scripted approach on a Windows machine is to use Python to read the MBOX file and use the Outlook COM interface (pywin32) to inject the emails directly into a new PST archive.

  1. You must run this on Windows with Microsoft Outlook installed.
  2. Install the required Python library: pip install pywin32

The Python Script

Save the code below as mbox_to_pst.py. It reads your MBOX file message by message and adds them to a newly created PST file via Outlook.

import os
import mailbox
import win32com.client
from email import policy
from email.parser import BytesParser

# --- CONFIGURATION ---
SOURCE_MBOX_DIR = r"C:\path\to\your\MBOX_Folder"  # Directory containing .mbox files/folders
OUTPUT_PST_PATH = r"C:\path\to\your\output.pst"
# ---------------------

def get_or_create_folder(parent_folder, folder_name):
    """Safely finds or creates a subfolder in Outlook."""
    try:
        return parent_folder.Folders.Item(folder_name)
    except Exception:
        return parent_folder.Folders.Add(folder_name)

def process_mbox_file(mbox_path, target_outlook_folder):
    """Parses an MBOX file and maps formatting/attachments to Outlook."""
    print(f"Processing: {os.path.basename(mbox_path)}")
    
    # Open file in binary mode to accurately extract attachments and formatting
    with open(mbox_path, 'rb') as f:
        mbox = mailbox.mbox(f)
        
        for index, msg_bytes in enumerate(mbox.itervalues(), 1):
            try:
                # Parse full message with formatting and layers intact
                msg = BytesParser(policy=policy.default).parsebytes(msg_bytes.as_bytes())
                
                # Create a blank mail item in the specific PST subfolder
                mail_item = target_outlook_folder.Items.Add(0) # 0 = olMailItem
                
                # Metadata
                mail_item.Subject = msg['subject'] or "(No Subject)"
                mail_item.To = msg['to'] or ""
                mail_item.CC = msg['cc'] or ""
                mail_item.BCC = msg['bcc'] or ""
                
                # Handle Formatting (HTML vs Plain Text)
                html_body = msg.get_body(preferencelist=('html'))
                text_body = msg.get_body(preferencelist=('plain'))
                
                if html_body:
                    mail_item.HTMLBody = html_body.get_content()
                elif text_body:
                    mail_item.Body = text_body.get_content()
                
                # Handle Attachments
                for part in msg.iter_attachments():
                    filename = part.get_filename()
                    if filename:
                        # Temporary save attachment to disk to load into Outlook
                        temp_path = os.path.join(os.environ['TEMP'], filename)
                        with open(temp_path, 'wb') as at_file:
                            at_file.write(part.get_content())
                        
                        mail_item.Attachments.Add(temp_path)
                        os.remove(temp_path) # Clean up
                
                # Save into the PST
                mail_item.Save()
                
            except Exception as e:
                print(f"   Error processing email #{index} in {os.path.basename(mbox_path)}: {e}")

def convert_all_mbox_to_pst():
    if not os.path.isdir(SOURCE_MBOX_DIR):
        print(f"Error: Source directory not found at {SOURCE_MBOX_DIR}")
        return

    print("Opening Outlook...")
    outlook = win32com.client.Dispatch("Outlook.Application")
    namespace = outlook.GetNamespace("MAPI")
    
    print(f"Mounting PST at: {OUTPUT_PST_PATH}")
    namespace.AddStore(OUTPUT_PST_PATH)
    pst_store = namespace.Stores.Item(namespace.Stores.Count)
    root_folder = pst_store.GetRootFolder()

    # Traverse directory to reconstruct folder structures
    for root, dirs, files in os.walk(SOURCE_MBOX_DIR):
        for file in files:
            if file.endswith('.mbox'):
                full_mbox_path = os.path.join(root, file)
                
                # Determine relative path structure
                rel_path = os.path.relpath(root, SOURCE_MBOX_DIR)
                current_target_folder = root_folder
                
                if rel_path != ".":
                    # Replicate nested folder path in Outlook
                    for folder_part in rel_path.split(os.sep):
                        current_target_folder = get_or_create_folder(current_target_folder, folder_part)
                
                # Create a specific folder for the file itself (minus .mbox extension)
                mbox_folder_name = os.path.splitext(file)[0]
                final_email_folder = get_or_create_folder(current_target_folder, mbox_folder_name)
                
                # Import
                process_mbox_file(full_mbox_path, final_email_folder)

    print("Detaching PST from Outlook...")
    namespace.RemoveStore(root_folder)
    print("Migration complete!")

if __name__ == "__main__":
    convert_all_mbox_to_pst()

Close Outlook before running the script so it can control the background automation smoothly. Because this interacts live with Outlook's engine, it can take some time if you have thousands of emails. For enormous archives (tens of gigabytes), you may want to look into modular toolkits like the mbox-to-pst-toolkit on GitHub which exports to raw .eml intermediate files first to prevent memory bottlenecks.

Note: PST is a proprietary Microsoft format, meaning Python cannot generate a true .pst file purely on its own without interacting with external libraries. That is why the above approach is actually using Outlook itself as part of the process. The script merely automates it all.

Easier Alternative

If the Python script fails or messes up email timestamps, the most accurate native approach is to install Mozilla Thunderbird (free), import your MBOX files using the ImportExportTools NG extension, configure your email account via IMAP, and let them sync naturally to the server so Outlook can download them flawlessly.

add a comment
0

User

Community

Market

Help Center

Legal

Company

Connect