---
title: "Convert a PST file to mbox in C#"
url: https://recursiveai.org/onemail/cookbook/convert-pst-to-mbox/
description: "Convert a PST or OST file to mbox in C#: one mbox per Outlook folder, calendar items and contacts as .ics and .vcf, and a loss report. Also OLM, DBX and Maildir. Runnable code with OneMail 0.3.0-preview.2."
version: "0.3.0-preview.2"
---

# Convert a PST file to mbox in C#

Call `Mail.ConvertAsync(source, ConvertFormat.Mbox, destination)`. It reads the store one message at a time and writes one mbox file per Outlook folder, the format most mail programs import. The same call takes OST, OLM, DBX, mbox and Maildir sources, and writes EML, Maildir, Apple Mail, ICS or vCard instead. The program below converts the PST test file of Apache Tika.

```shell
dotnet new console -o PstToMbox && cd PstToMbox
dotnet add package RecursiveAI.OneMail --version 0.3.0-preview.2
curl -LO https://raw.githubusercontent.com/apache/tika/4.2.0/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testPST.pst
```

Put this in `Program.cs` and run `dotnet run` (or `dotnet run -- yourfile.pst`):

```csharp
using RecursiveAI.OneMail;
using RecursiveAI.OneMail.Conversion.Stores;

string source = args.Length > 0 ? args[0] : "testPST.pst";

// One .mbox per folder under "mbox"; calendar items and contacts go to mbox/_items
StoreConversionReport report = await Mail.ConvertAsync(source, ConvertFormat.Mbox, "mbox");

Console.WriteLine($"read {report.ItemsRead}, written {report.ItemsWritten}, skipped {report.ItemsSkipped}");
foreach (var (folder, count) in report.Folders)
    Console.WriteLine($"  {folder}: {count.Written} of {count.Read}");

// What didn't carry over, by code, most frequent first
foreach (LossTotal loss in report.Losses.Take(5))
    Console.WriteLine($"  {loss.Kind} {loss.Code} in {loss.Items} items, e.g. {loss.Example}");

foreach (string file in Directory.GetFiles("mbox", "*", SearchOption.AllDirectories))
    Console.WriteLine($"{file}  {new FileInfo(file).Length:N0} bytes");
```

```text
read 7, written 7, skipped 0
  Début du fichier de données Outlook: 7 of 7
  Approximated DefaultValueNotWritten in 7 items, e.g. PidTagSensitivity
  Dropped NoInternetMapping in 7 items, e.g. PidTagPriority
  Internal StoreBookkeeping in 7 items, e.g. PidTagSentRepresentingSearchKey
  Approximated SubjectPrefixMarkerRemoved in 7 items, e.g. PidTagSubject
  Internal FlagsWrittenAsHeaders in 7 items, e.g. Status
mbox/Début du fichier de données Outlook.mbox  69,216 bytes
```

Python’s `mailbox` module reads the seven messages back from the file.

## The report

Every message is accounted for: items read always equal items written plus items skipped, and `SkippedByReason` says why any were skipped. `Losses` totals what didn’t carry over across the run, by code. Outlook properties with no internet form (`NoInternetMapping`), the transport headers rewritten for the new message, and reply-to entries with no address are the usual ones. Pass an `IProgress<StoreItemResult>` to see each message’s own report as it’s written.

## Options

- **One file.** A destination with an extension, such as `"all.mbox"`, writes a single mbox; folders are flattened and the report says so.
- **Other formats.** `ConvertFormat.Eml`, `Maildir` (Maildir++ subfolders with flags), `AppleMail`, `Ics`, `VCard` and their JSON and XML forms, or `Tnef`.
- **Skip calendars and contacts.** `new StoreConversionOptions { OtherItems = OtherItemsMode.Skip }`.
- **One folder.** `FolderFilter = "Inbox"` converts that folder and the folders under it.
- **From the command line**, the same conversion: `onemail convert --to mbox testPST.pst mbox`.

## Limits

- **A preview.** 0.3.0-preview.2: the API can change before 1.0.
- **Not to Outlook.** In the project’s words: “MSG and PST are not destinations until 0.5”.
- **Outlook flags.** “flags and keywords from Outlook items (`PidTagFlagStatus`, last verb) are mapped by rule and not yet observed in Outlook”.
- **Exchange addresses.** There is no directory lookup: “EX addresses with no SMTP form in the item are left out and reported”.

What carries over for each source and target: [Store to store and fidelity](https://recursiveai.org/onemail/docs/fidelity/). One message at a time: [Convert a PST file to EML](https://recursiveai.org/onemail/cookbook/convert-pst-to-eml/).
