Introduction
Eventually, there may come a time where we want to convert our Outlook PST (Personal Storage File) files to live on our hard drives as Outlook .msg files instead of within a PST file itself. Perhaps your company prevents the use of PST files or perhaps it has just grown out of control. Moving messages from the PST file to the hard drive also may give us better searchability, using Windows Search. This article will quickly show you how to move email messages from a PST file to your hard drive.
Background
To deal with Outlook in a .NET application, we need an interface named MAPI. MAPI stands for Messaging Application Programming Interface and is provided by Microsoft for Outlook programming. Using MAPI, we can access folders like Inbox, Drafts, Sent Items and so on that reside in a PST file. We can even create sessions and namespace to fetch items from Outlook or, say, from a PST file. Currently, MAPI is the only namespace provided by Microsoft to extract PST files. For further information on MAPI, I suggest newbies visit the relevant MSDN article.
Using the Code
To get started:
- Open Visual Studio and create a new Console application.
- When the console application is ready, assuming you have Outlook installed (this is a necessity for this article), you'll need to add a reference to the Microsoft.Office.Interop.Outlook.dll assembly (mine was found at C:\Program Files (x86)\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA\Office14).
- Copy/paste the following code and execute it.
The code will prompt you for a file path to write the main items to, then to choose a PST file already added to your Outlook instance, recursively iterate all folders and subfolders, and finally extract each mailItem to the root folder defined.
Alternatively, if you'd rather choose a disconnected PST file, you could update the code to manually add and remove the PST file by using the AddStore
/RemoveStore
method of the outlookNs
namespace object and define a path for it. The rest of the code would be basically the same.
using System;
using Microsoft.Office.Interop.Outlook;
using System.Text.RegularExpressions;
namespace PSTMover
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter folder path to write
PST Mail Items to (i.e. c:\\temp\\Email): ");
String OutputRootPath = Console.ReadLine();
if (System.IO.Directory.Exists(OutputRootPath) == false)
return;
WritePSTFilesToFolder(OutputRootPath);
}
private static void WritePSTFilesToFolder(String OutputPath)
{
Application app = new Application();
NameSpace outlookNs = app.GetNamespace("MAPI");
MAPIFolder RootFolder = outlookNs.PickFolder();
if(RootFolder!=null) foreach (MAPIFolder SubFolder in RootFolder.Folders)
{
Iterate(SubFolder, OutputPath);
}
}
private static void Iterate(MAPIFolder RootFolder, String OutputPath)
{
OutputPath = OutputPath + RemoveFileNameSpecialChars(RootFolder.Name) + @"\";
WriteEmails(RootFolder, OutputPath);
foreach (MAPIFolder SubFolder in RootFolder.Folders)
{
Iterate(SubFolder, OutputPath);
}
}
private static void WriteEmails(MAPIFolder Folder, String OutputPath)
{
Items items = Folder.Items;
foreach (object item in items)
{
if (item is MailItem)
{
MailItem mailItem = item as MailItem;
Console.WriteLine("Saving message {0} .... into {1}", mailItem.Subject, OutputPath);
if (System.IO.Directory.Exists(OutputPath) == false)
{
System.IO.Directory.CreateDirectory(OutputPath);
}
try
{
String Subject = mailItem.Subject;
if (Subject == null)
Subject = "NULL";
String FilePathName = OutputPath + RemoveFileNameSpecialChars
(Subject.Replace('\u0009'.ToString(), "")) + ".msg"; mailItem.SaveAs(FilePathName, OlSaveAsType.olMSG);
System.IO.File.SetCreationTime(FilePathName, mailItem.ReceivedTime);
System.IO.File.SetLastWriteTime(FilePathName, mailItem.ReceivedTime);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
public static String RemoveFileNameSpecialChars(string FileName)
{
Regex regex = new Regex(@"[\w\s-'.,]");
String validName = FileName;
for (int i = 0; i < FileName.Length; i++)
{
Boolean matched = regex.IsMatch(FileName[i].ToString());
if (matched == false)
{
validName = validName.Replace(FileName[i].ToString(), "");
}
}
return validName;
}
}
}
History
- 30th March, 2016 -- Initial version