读取和转换 Outlook 文件

使用 OST 文件

Aspose.Email for .NET 提供了读取 Microsoft Outlook OST 文件的 API。您可以将 OST 文件从磁盘或流加载到一个实例中 Aspose.Email.Outlook.Pst.PersonalStorage 用于访问其内容的类,例如文件夹、子文件夹和邮件。当使用 POP3 或 IMAP 邮件服务器时,Microsoft Outlook 会创建 PST 文件来存储邮件。相反,当使用 Microsoft Exchange 作为邮件服务器时,会创建 OST 文件。OST 文件也支持比 PST 文件更大的文件大小。

读取 OST 文件

使用 Aspose.Email 读取 OST 文件的过程与读取 PST 文件完全相同。相同的代码可以读取 PST 和 OST 文件:只需向 PersonalStorage.FromFile() 方法。下面的代码片段演示了如何读取 OST 文件。

将 OST 转换为 PST

Aspose.Email 只需一行代码即可将 OST 文件转换为 PST。同样,也可以使用同一行代码通过 PST 文件创建 OST 文件,使用 FileFormat 枚举器。目前 API 支持将 OST 格式转换为 PST 除 2013/2016/2019/2021 及以后版本外。下面的代码片段展示了如何将 OST 转换为 PST。

欲进行其他 OST 文件操作,请参阅以下页面:

将 PST 转换为 OST

Aspose.Email 不支持将 PST 转换为 OST,因为 OST 始终由 Outlook 在添加账户并与邮件服务器同步时创建。PST 与 OST 的区别在于 PST 仅在本地可用,而 OST 内容也在邮件服务器上可用。因此无需将 PST 转换为 OST 以供本地使用。但可以使用 Outlook 的导入/导出向导将 PST 导入现有账户。

OLM 是 Microsoft Outlook 用于存储本地数据(如电子邮件、附件、笔记、日历数据、联系人、任务、历史记录等)的专有文件格式。OLM 文件仅与 Outlook for Mac 兼容,无法在使用 PST 文件格式的 Windows 版 Outlook 中打开或访问。

使用 OLM 文件

打开 OLM 文件

OLM 格式文件可以通过两种方式打开:

  • 使用构造函数
  • 使用静态 FromFile 方法

这些方法在行为上存在差异。请参阅下文。

使用构造函数

要打开文件,请调用 OlmStorage 类并将完整文件名或流作为参数传入:

var fileName = "MyStorage.olm";
var olm = new OlmStorage(fileName);

使用静态方法 FromFile

要打开文件,请使用静态方法 FromFile 并将完整文件名或流作为参数传入:

var fileName = "MyStorage.olm";
var olm = OlmStorage.FromFile(fileName);

检索文件夹

要访问 OLM 文件的目录结构,请创建以下类的实例: OlmStorage 类,使用其构造函数并传入文件路径。文件打开后,使用以下方式访问其目录结构: FolderHierarchy 属性。该属性返回一个列表,包含 OlmFolder 对象,每个代表 OLM 文件中的一个目录。要进一步探索目录结构,请访问 SubFolders 每个对象的属性,返回其子目录的列表。通过使用这些属性,您可以遍历 OLM 文件的整个目录层次结构,访问其中包含的所有目录和子目录。

下面的示例按层级顺序显示所有文件夹的列表:

using (var olm = new OlmStorage(fileName))
{
    PrintAllFolders(olm.FolderHierarchy, string.Empty);
}

private void PrintAllFolders(List<OlmFolder> folderHierarchy, string indent)
{
    foreach (var folder in folderHierarchy)
    {
        Console.WriteLine($"{indent}{folder.Name}");
        PrintAllFolders(folder.SubFolders, indent+"-");
    }
}

使用 FromFile 方法打开 OLM 文件, FolderHierarchy 属性默认不会被初始化,返回 null。在这种情况下,需要显式调用 GetFolders 方法来初始化它。 FolderHierarchy 属性并检索 OLM 文件中的目录列表:

using (var olm = OlmStorage.FromFile(fileName))
{
    var folders = olm.GetFolders();
}

另外,也可以通过名称获取任意文件夹:

  1. 调用 GetFolder 方法。
  2. 将文件夹名称作为第一个参数,第二个参数传入一个值,指示在搜索文件夹时是否忽略大小写。
using (var olm = OlmStorage.FromFile(fileName))
{
    // get inbox folder by name
    OlmFolder folder = olm.GetFolder("Inbox", true);
}

列出邮件

OlmFolder 类,表示文件夹,具有以下获取邮件列表的方法:

  • EnumerateMessages 实现了文件夹中邮件的迭代。在这种情况下,每次迭代返回 OlmMessageInfo 对象,提供邮件的简要信息。
  • EnumerateMapiMessages,也实现了文件夹中邮件的迭代,但在这种情况下,每次迭代返回 MapiMessage 对象,表示邮件本身,包含所有属性。

使用 EnumerateMessages 方法

using (var olm = OlmStorage.FromFile(fileName))
{
    var folder = olm.GetFolder("Inbox", true);
    foreach (var messageInfo in folder.EnumerateMessages())
    {
        Console.WriteLine(messageInfo.Subject);
    }
}

使用 EnumerateMapiMessages 方法

using (var olm = OlmStorage.FromFile(fileName))
{
    var folder = olm.GetFolder("Inbox", true);

    foreach (var msg in folder.EnumerateMapiMessages())
    {
        // save message in MSG format
        msg.Save($"{msg.Subject}.msg");
    }
}

其他有用属性

OlmFolder 类的其他有用属性如下: HasMessagesMessageCount 属性,返回文件夹中是否存在邮件以及它们的数量。

using (var olm = OlmStorage.FromFile(fileName))
{
    var folder = olm.GetFolder("Inbox", true);

    if (folder.HasMessages)
    {
        Console.WriteLine($"Message count: {folder.MessageCount}");
    }
}

获取或设置消息的修改日期

修改日期表示 OLM 邮件最后一次修改的日期和时间。您可以使用 OlmMessageInfo.ModifiedDate 用于检索或更新 OLM 邮件修改日期值的属性。

以下示例演示了该属性的用法:

foreach (OlmMessageInfo messageInfo in inboxFolder.EnumerateMessages())
{
   DateTime modifiedDate = messageInfo.ModifiedDate;
}

提取电子邮件和项目

OlmStorage 类拥有 ExtractMapiMessage 允许提取电子邮件的方法。此方法接收一个 OlmMessageInfo 对象。

using (var olm = OlmStorage.FromFile(fileName))
{
    var folder = olm.GetFolder("Inbox", true);

    foreach (var messageInfo in folder.EnumerateMessages())
    {
        if (messageInfo.Date == DateTime.Today)
        {
            // Extracts today's messages form Inbox
            var msg = olm.ExtractMapiMessage(messageInfo);
        }
    }
}

使用遍历 API

即使原始文件的部分数据已损坏,也可以尽可能提取 Outlook OLM 文件中的所有项目,而不会抛出异常。要实现此功能,请使用 OlmStorage(TraversalExceptionsCallback callback) 构造函数和 Load(string fileName) 使用该方法而不是 FromFile 方法。构造函数允许定义回调方法。

using (var olm = new OlmStorage((exception, id) => { /* Exception handling  code. */ }))

回调方法会将加载和遍历过程中的异常暴露出来。

Load 如果文件成功加载且可以继续遍历,方法返回 ’true’。如果文件已损坏且无法遍历,则返回 ‘false’。

if (olm.Load(fileName))

以下代码片段和步骤展示了如何使用此 API:

  1. 创建该类的新实例 OlmStorage 类,传入异常处理回调以处理过程中的任何异常。
  2. 通过调用以下方法加载 OLM 文件: Load OlmStorage 实例的方法。
  3. 如果 OLM 文件成功加载,可通过调用以下方法获取文件夹层次结构: GetFolders 在 OlmStorage 实例上的方法。它返回 OlmFolder 对象的列表。
  4. 调用 ExtractItems 方法,传入 OlmStorage 实例和 OlmFolder 对象列表。
  5. 在 ExtractItems 方法中,遍历 folders 列表中的每个文件夹。
  6. 如果文件夹包含消息(电子邮件),使用 Console.WriteLine(folder) 将文件夹名称打印到控制台。
  7. 通过在 OlmStorage 实例上调用 EnumerateMessages 方法,并传入当前文件夹作为参数,遍历当前文件夹中的消息。
  8. 使用 Console.WriteLine(msg.Subject) 将每条消息的主题打印到控制台。
  9. 如果文件夹有子文件夹,递归调用 ExtractItems 方法,传入 OlmStorage 实例以及当前文件夹的子文件夹。
using (var olm = new OlmStorage((exception, id) => { /* Exception handling  code. */ }))
{
    if (olm.Load(fileName))
    {
        var folderHierarchy = olm.GetFolders();
        ExtractItems(olm, folderHierarchy);
    }
}

private static void ExtractItems(OlmStorage olm, List<OlmFolder> folders)
{
    foreach (var folder in folders)
    {
        if (folder.HasMessages)
        {
            Console.WriteLine(folder);

            foreach (var msg in olm.EnumerateMessages(folder))
            {
                Console.WriteLine(msg.Subject);
            }
        }

        if (folder.SubFolders.Count > 0)
        {
            ExtractItems(olm, folder.SubFolders);
        }
    }
}

按标识符提取邮件

有时需要按标识符提取特定邮件。例如,您的应用程序将标识符存储在数据库中,并按需提取邮件。这是一种高效的方式,可避免每次遍历整个存储以查找要提取的特定邮件。此功能适用于 OLM 存储。该 EntryId 属性的 OlmMessageInfo 类获取邮件条目标识符。重载的 ExtractMapiMessage(string id) 方法的 OlmStorage 类从 OLM 获取邮件。

下面的代码展示了如何按标识符从 OLM 提取邮件。

代码执行以下步骤:

  1. 启动 foreach 循环遍历列表中的 OlmMessageInfo 对象。循环使用 EnumerateMessages olmFolder 对象的方法,以检索当前遍历的文件夹中的所有邮件列表。
  2. 循环通过调用 ExtractMapiMessage(string id) 方法的 OlmStorage 类,传入 EntryId 作为参数传递当前邮件的

检索到的 MapiMessage 对象可用于访问和操作邮件内容。循环将持续,直至文件夹中的所有邮件都被处理完毕。

  foreach (OlmMessageInfo msgInfo in olmFolder.EnumerateMessages())
  {
      MapiMessage msg = storage.ExtractMapiMessage(msgInfo.EntryId);
  }

获取文件夹路径

您也可以获取 OML 文件中各文件夹的路径。Aspose.Email 提供了 OlmFolder.Path 返回文件夹路径的属性。以下代码片段演示了其用法 OlmFolder.Path 用于获取 OML 文件中文件夹路径的属性。

var storage = new OlmStorage("SampleOLM.olm");
PrintPath(storage, storage.FolderHierarchy);

public static void PrintPath(OlmStorage storage, List<OlmFolder> folders)
{
    foreach (OlmFolder folder in folders)
    {
        // print the current folder path
        Console.WriteLine(folder.Path);

        if (folder.SubFolders.Count > 0)
        {
            PrintPath(storage, folder.SubFolders);
        }
    }
}

统计文件夹中的项目数

您也可以统计文件夹中项目的数量。Aspose.Email 提供了 OlmFolder.MessageCount 返回文件夹中项目数量的属性。以下代码片段演示了其用法 OlmFolder.MessageCount 用于获取 OML 文件中文件夹项目数量的属性。

var storage = new OlmStorage("SampleOLM.olm");
PrintMessageCount(storage.FolderHierarchy);

public static void PrintMessageCount(List<OlmFolder> folders)
{
    foreach (OlmFolder folder in folders)
    {
        Console.WriteLine("Message Count [" + folder.Name + "]: " + folder.MessageCount);
    }
}

获取 OlmStorage 的总项目计数

OlmStorage 类还具有 GetTotalItemsCount() 返回 OLM 存储中邮件项目总数的方法。

  using (var olm = new OlmStorage("storage.olm"))
  {
     var count = olm.GetTotalItemsCount();
  }

Outlook 类别颜色检索

要处理存储在 OLM 文件中的类别颜色或 Outlook 项目类别,Aspose.Email 提供以下解决方案:

以下代码示例演示了如何从 OML 存储中获取所有已使用的类别:

using (var olm = OlmStorage.FromFile("storage.olm"))
{
    var categories = olm.GetCategories();
    
    foreach (var category in categories)
    {
        Console.WriteLine($"Category name: {category.Name}");
        
        //Color is represented as a hexadecimal value: #rrggbb
        Console.WriteLine($"Category color: {category.Color}");
    }
}

下面的代码示例展示了如何获取邮件类别颜色:

foreach (var msg in olm.EnumerateMessages(folder))
{
    if (msg.Categories != null)
    {
        foreach (var msgCategory in msg.Categories)
        {
            Console.WriteLine($"Category name: {msgCategory}");
            var categoryColor = cat.First(c => c.Name.Equals(msgCategory, StringComparison.OrdinalIgnoreCase)).Color;
            Console.WriteLine($"Category color: {categoryColor}");
        }
    }
}

将 OLM 转换为 PST

OLM 是一种由 Microsoft Outlook for Mac 系统使用的数据库文件格式。OLM 文件存储电子邮件、日历数据、联系人数据以及应用设置。Windows 版 Outlook 不支持 OLM 文件。因此,无法在 Windows 版 Outlook 中打开 Mac 版 Outlook(OLM)文件。如果您想将邮箱从 Mac 版 Outlook 迁移到 Windows 版 Outlook,需要将 Mac 版 Outlook 的 OLM 文件转换为 Outlook PST 文件格式。

代码步骤

要将 OLM 文件转换为 PST,请按照以下步骤操作:

  1. 创建以下实例: OlmStorage 用于打开源 OLM 的类。
  2. 打开源 OLM 文件。
  3. 使用以下方式创建新 PST 文件 Create 方法。
  4. 创建一个 GetContainerClass 方法,将邮件类映射到文件夹类。
  5. 创建一个 AddToPst 方法,使用 EnumerateMapiMessages 方法递归读取 OLM 中的每个文件夹及其邮件,并使用 AddSubFolder 和 AddMessage 方法按相同顺序将它们添加到 PST 中。

代码示例

以下代码示例展示了如何将 OLM 转换为 PST。

Main 方法:

// create an instance of OlmStorage class to open source OLM
using (var olm = new OlmStorage("my.olm"))
// create a new PST file
using (var pst = PersonalStorage.Create("my.pst", FileFormatVersion.Unicode))
{
    // recursively reads each folder and its messages 
    // and adds them to the PST in the same order
    foreach (var olmFolder in olm.FolderHierarchy)
    {
        AddToPst(pst.RootFolder, olmFolder);
    }
} 

GetContainerClass 方法实现:

public string GetContainerClass(string messageClass)
{
    if (messageClass.StartsWith("IPM.Contact") || messageClass.StartsWith("IPM.DistList"))
    {
        return "IPF.Contact";
    }

    if (messageClass.StartsWith("IPM.StickyNote"))
    {
        return "IPF.StickyNote";
    }

    if (messageClass.StartsWith("IPM.Activity"))
    {
        return "IPF.Journal";
    }

    if (messageClass.StartsWith("IPM.Task"))
    {
        return "IPF.Task";
    }

    if (messageClass.StartsWith("IPM.Appointment") || messageClass.StartsWith("IPM.Schedule.meeting"))
    {
        return "IPF.Appointment";
    }

    return "IPF.Note";
}

AddToPst 方法实现:

public void AddToPst(FolderInfo pstFolder, OlmFolder olmFolder)
{
    FolderInfo pstSubFolder = pstFolder.GetSubFolder(olmFolder.Name);

    foreach (var msg in olmFolder.EnumerateMapiMessages())
    {
        if (pstSubFolder == null)
        {
            pstSubFolder = pstFolder.AddSubFolder(olmFolder.Name, GetContainerClass(msg.MessageClass));
        }

        pstSubFolder.AddMessage(msg);
    }

    if (pstSubFolder == null)
    {

        pstSubFolder = pstFolder.AddSubFolder(olmFolder.Name);
    }

    foreach (var olmSubFolder in olmFolder.SubFolders)
    {
        AddToPst(pstSubFolder, olmSubFolder);
    }
}