9.8 KiB
PST Email Extractor
A command-line tool that scans a directory for Outlook PST files and extracts the metadata of every email — subject, sender, recipients, date, size, attachments count, and message class — into individual CSV files.
Table of Contents
- Features
- Requirements
- Installation
- Usage
- Output Format
- How It Works
- Performance Notes
- Troubleshooting
- Platform-specific pypff Installation
- Project Structure
- FAQ
Features
- Batch processing – drop any number of
.pstfiles in a folder and run once - Resilient extraction – corrupt messages are skipped gracefully; processing continues
- Rich metadata – exports 8 fields per message including attachment count and message class
- Progress bars – real-time per-file progress via
tqdm - UTF-8 output – fully compatible with Excel, Google Sheets, and any modern CSV tool
- Iterative folder traversal – avoids Python recursion limits on deeply nested PST archives
- Human-friendly summaries – per-run statistics on success / failure counts
Requirements
| Dependency | Version | Purpose |
|---|---|---|
| Python | ≥ 3.8 | Runtime |
tqdm |
≥ 4.66 | Progress bars |
pypff / libpff-python |
any | PST file reading |
Note:
pypffwraps the native C library libpff. Installation varies by platform — see Platform-specific pypff Installation.
Installation
Step 1 – Clone or download the project
Place Extract.py and install_dependencies.py in the same directory.
Step 2 – Run the dependency installer
python install_dependencies.py
This script will:
- Upgrade
pip,setuptools, andwheel. - Install
tqdmvia pip. - Attempt to install
libpff-python/pypffvia pip. - Print platform-specific instructions if the automatic install fails.
Step 3 – Verify
python -c "import pypff; import tqdm; print('All good!')"
Usage
Basic usage (process PST files in the script's own directory)
python Extract.py
Specify a directory
python Extract.py /path/to/pst/folder
# Windows PowerShell
python Extract.py "C:\Users\You\Desktop\PST_Files"
Example output
📂 Working directory: /data/pst_files
================================================================================
🔍 SEARCHING FOR PST FILES
================================================================================
✓ Found 3 PST file(s)
📁 PST Files:
1. archive_2021.pst (1,204.3 MB)
2. archive_2022.pst (876.1 MB)
3. personal.pst (312.7 MB)
================================================================================
🚀 PROCESSING
================================================================================
────────────────────────────────────────────────────────────────────────────────
📊 1/3 | ✓ Done: 0 | ❌ Failed: 0 | ⏳ Remaining: 2
🔄 archive_2021.pst
📊 Counting messages in archive_2021.pst …
✓ 42,817 messages found
Processing archive_2021.pst: 100%|████████| 42817/42817 [02:14<00:00]
✓ Written 42,817 rows | Errors skipped: 3
✅ Saved → archive_2021_email_list.csv (42,817 rows)
Output Format
For each input file <name>.pst, a corresponding <name>_email_list.csv is created in the same directory.
CSV columns
| Column | Description | Max Length |
|---|---|---|
Folder |
Full folder path inside the PST (e.g. Inbox\Projects\2022) |
200 chars |
Subject |
Email subject line | 500 chars |
From |
Sender name and/or email address | 200 chars |
To |
Semicolon-separated recipient list | 1000 chars |
Date |
Delivery or submit time in YYYY-MM-DD HH:MM:SS UTC |
— |
Size |
Estimated message size in bytes (sum of body and headers) | — |
Attachments |
Number of attachments | — |
MessageClass |
MAPI message class (e.g. IPM.Note, IPM.Appointment) |
100 chars |
Example rows
Folder,Subject,From,To,Date,Size,Attachments,MessageClass
Inbox,Q3 Budget Review,Alice Smith <alice@example.com>,bob@example.com,2023-09-01 14:22:10 UTC,18432,2,IPM.Note
Sent Items,Re: Proposal,Bob Jones <bob@example.com>,alice@example.com,2023-09-02 09:05:44 UTC,4210,0,IPM.Note
Calendar,,Alice Smith <alice@example.com>,,2023-10-10 09:00:00 UTC,1024,0,IPM.Appointment
How It Works
- Discovery –
find_pst_files()usesglobto locate all.pstfiles in the given directory. - Counting – Before extraction,
count_total_messages()recursively counts all messages sotqdmcan show an accurate progress bar. - Traversal –
process_folder()uses an iterative stack (not Python recursion) to walk the full folder tree, guarding against deep nesting and corrupt nodes. - Extraction –
extract_email_info()wraps every individual attribute access in atry/exceptso one corrupt property never aborts the whole message. - Writing – Results are streamed directly to a UTF-8 CSV file via
csv.writer, keeping memory usage flat regardless of PST size. - Error recovery – Failed messages are counted and reported in the summary but do not interrupt processing.
Performance Notes
- Memory – The extractor streams rows directly to disk, so even a 50 GB PST file won't exhaust RAM.
- Speed – Processing speed depends on your disk I/O. SSDs can process ~5,000–15,000 messages/min; spinning disks are 3–5× slower.
- Large recipient lists – Recipient lists are capped at 100 entries and 1,000 characters to avoid giant rows.
- Iterative traversal – The folder walker uses an explicit stack instead of recursion, making it safe for PST archives with hundreds of nested folders.
Troubleshooting
ModuleNotFoundError: No module named 'pypff'
Run python install_dependencies.py. If the automatic install fails, see Platform-specific pypff Installation.
Failed to open PST file
- The file may be in use by Outlook. Close Outlook completely and try again.
- The file may be corrupted. Try running the Outlook Inbox Repair Tool (
scanpst.exeon Windows).
Progress bar reaches 100% but fewer rows are written than expected
This is normal. Some items in a PST folder hierarchy are not email messages (calendar events, contacts, tasks). They are counted in the total but may fail extraction silently. The Errors skipped count in the summary reflects this.
CSV opens with garbled characters in Excel
The CSV is UTF-8. In Excel, use Data → From Text/CSV and choose UTF-8 encoding, or open via File → Open and select the encoding in the import wizard.
Very slow processing on large PST files
Ensure the PST file is on a local drive, not a network share or cloud-synced folder. Network latency multiplies enormously across hundreds of thousands of small reads.
Platform-specific pypff Installation
Linux (Debian / Ubuntu)
sudo apt-get install python3-libpff
# or
pip install libpff-python
Linux (Fedora / RHEL)
sudo dnf install libpff-devel python3-libpff
macOS (Homebrew)
brew install libpff
pip install libpff-python
Windows
Automatic pip installation may fail because libpff requires compilation.
Option 1 – Pre-built wheel (if available for your Python version):
pip install libpff-python
Option 2 – Build from source – follow the official guide: https://github.com/libyal/libpff/blob/main/documentation/Building.md
Option 3 – WSL (recommended) – Install Windows Subsystem for Linux, then follow the Ubuntu steps above. This is the easiest path for most Windows users.
Project Structure
.
├── Extract.py # Main extractor – run this
├── install_dependencies.py # One-time dependency installer
└── README.md # This file
Outputs are placed alongside the input PST files:
/your/pst/folder/
├── archive_2021.pst
├── archive_2021_email_list.csv ← generated
├── archive_2022.pst
└── archive_2022_email_list.csv ← generated
FAQ
Does the tool modify the PST files? No. PST files are opened read-only. The tool never writes to them.
Can I run it on a single PST file instead of a whole directory?
Put the PST file in its own folder and pass that folder path. Alternatively, the function export_pst_to_csv(pst_path, output_csv_path) can be imported and called directly from your own script.
What happens if I run it twice on the same directory? Existing CSV files are overwritten without warning. If you want to preserve previous results, move or rename them first.
Does it export email bodies or attachments? No — only metadata is exported. This keeps the output small and avoids legal / privacy issues associated with exporting full message content.
What message types are included?
All MAPI message objects found in the PST: emails (IPM.Note), meeting requests (IPM.Schedule.*), appointments (IPM.Appointment), contacts (IPM.Contact), tasks (IPM.Task), etc. The MessageClass column lets you filter by type in your spreadsheet.
Will it work with OST files?
libpff has partial OST support. Rename the file to .pst and try — results may vary depending on the OST version and whether the file is currently synced.
For bug reports and feature requests, open an issue in your project repository.