如何在 C++ 中将 EML 转换为 MSG

如何在 C++ 中将 EML 转换为 MSG

本指南展示了如何在 C++ 中使用 mapi_message::load_from_eml() 和 mapi_message::save() 将 EML 文件转换为 Outlook MSG 格式,以及如何使用 mapi_message::from_file() 和 mapi_message::save_to_eml() 将 MSG 转回 EML。

步骤 1 — 设置项目

从 GitHub 克隆 Aspose.Email FOSS for C++ 仓库,以将其添加为 CMake 子目录:

git clone https://github.com/aspose-email-foss/Aspose.Email-FOSS-for-Cpp.git

将子目录添加到你的 CMake 项目并链接目标库:

add_subdirectory(Aspose.Email-FOSS-for-Cpp)
target_link_libraries(your_target PRIVATE AsposeEmailFoss::AsposeEmailFoss)

步骤 2 — 将 EML 转换为 MSG(文件路径)

mapi_message::load_from_eml() 解析 EML 文件,并通过标准的 mapi_message 接口公开其属性。调用 save() 将结果写为 MSG:

#include <filesystem>
#include <iostream>
#include "aspose/email/foss/msg/mapi_message.hpp"

int main()
{
    const auto message = aspose::email::foss::msg::mapi_message::load_from_eml(
        std::filesystem::path("message.eml"));

    std::cout << "Subject: " << message.subject() << '\n';
    std::cout << "From:    " << message.sender_email_address() << '\n';

    message.save(std::filesystem::path("converted.msg"));
    std::cout << "Saved converted.msg\n";
}

步骤 3 — 将 EML 转换为 MSG(流)

当 EML 数据来自网络套接字、内存缓冲区或其他 std::istream 时,请使用 load_from_eml() 的流重载:

#include <fstream>
#include <filesystem>
#include "aspose/email/foss/msg/mapi_message.hpp"

int main()
{
    std::ifstream eml_stream("message.eml", std::ios::binary);
    const auto message = aspose::email::foss::msg::mapi_message::load_from_eml(eml_stream);

    message.save(std::filesystem::path("converted.msg"));
}

步骤 4 — 将 MSG 转换为 EML

使用 mapi_message::from_file() 加载现有的 MSG 文件,然后使用 save_to_eml() 将其序列化为 EML 格式:

#include <filesystem>
#include <iostream>
#include "aspose/email/foss/msg/mapi_message.hpp"

int main()
{
    const auto message = aspose::email::foss::msg::mapi_message::from_file(
        std::filesystem::path("sample.msg"));

    message.save_to_eml(std::filesystem::path("exported.eml"));
    std::cout << "Saved exported.eml\n";
}

步骤 5 — 完整往返(EML → MSG → EML)

下面的示例演示了主题、正文、发件人、收件人以及附件在完整往返过程中都得以保留:

#include <filesystem>
#include <iostream>
#include "aspose/email/foss/msg/mapi_message.hpp"

int main()
{
    const auto msg_path = std::filesystem::path("roundtrip.msg");
    const auto eml_out  = std::filesystem::path("roundtrip.eml");

    // EML → MSG
    auto message = aspose::email::foss::msg::mapi_message::load_from_eml(
        std::filesystem::path("original.eml"));
    message.save(msg_path);

    // MSG → EML
    auto reloaded = aspose::email::foss::msg::mapi_message::from_file(msg_path);
    reloaded.save_to_eml(eml_out);

    std::cout << "Subject preserved: " << reloaded.subject() << '\n';
    std::cout << "Attachments: " << reloaded.attachments().size() << '\n';
}

步骤 6 — 转换为内存中的 EML 字节

save() 和 save_to_eml() 都拥有零参数重载,返回 std::vector<std::uint8_t>,可用于在不触及文件系统的情况下将结果流式传输到网络连接或数据库:

#include <filesystem>
#include "aspose/email/foss/msg/mapi_message.hpp"

int main()
{
    const auto message = aspose::email::foss::msg::mapi_message::load_from_eml(
        std::filesystem::path("message.eml"));

    // In-memory MSG bytes
    const auto msg_bytes = message.save();

    // In-memory EML bytes
    const auto eml_bytes = message.save_to_eml();
}

常见问题与解决方案

load_from_eml() 在看似有效的 EML 文件上抛出异常。 验证文件使用 RFC 5322 CRLF 换行。某些工具导出的 EML 文件可能仅使用 LF。库期望符合标准的换行方式。

在 EML → MSG 转换后缺少附件。 确认 EML 包含标准的 MIME multipart/mixed or multipart/related 附件部分。通过以下方式引用的内联图像 cid: 作为附件包含在 MSG 中,应该存在。

HTML 正文在 MSG → EML 之后丢失。 HTML 内容在往返过程中得以保留,当 message.html_body() 非空。如果仅 message.body() 已在源 MSG 中填充,EML 将仅包含纯文本部分。

save_to_eml() 流输出为空。 使用以下方式打开输出流 std::ios::binary。文本模式流会在 Windows 上破坏 MIME 结构。

主题包含 ?= 编码伪影。 这些是原始 EML 中的 RFC 2047 编码词序列。库会原样保留它们。如果需要纯 Unicode 主题,请使用 RFC 2047 库进行解码。

常见问题

附件在两种转换方向上都会被保留吗?

是的。EML → MSG 和 MSG → EML 两种转换都会通过 mapi_message 附件列表携带所有 MIME 附件。二进制附件在 mapi_attachment::data 中以原始字节表示。

EML → MSG 是否会保留 HTML 正文?

是的。如果 EML 包含一个 text/html MIME 部分,它会被存储在 MAPI HTML 正文属性中,并在加载后由 message.html_body() 返回。

我可以批量转换一个包含 EML 文件的目录吗?

是的。使用 std::filesystem::directory_iterator 遍历目录,对每个 .eml 路径调用 mapi_message::load_from_eml(),然后使用 save() 保存:

#include <filesystem>
#include "aspose/email/foss/msg/mapi_message.hpp"

int main()
{
    for (const auto& entry : std::filesystem::directory_iterator("emails/"))
    {
        if (entry.path().extension() == ".eml")
        {
            auto msg = aspose::email::foss::msg::mapi_message::load_from_eml(entry.path());
            auto out = entry.path();
            out.replace_extension(".msg");
            msg.save(out);
        }
    }
}

在 EML ↔ MSG 转换过程中会保留哪些内容?

主题、纯文本正文、HTML 正文、发件人姓名和电子邮件地址、收件人列表以及所有 MIME 附件。IMAP 标志、除基本传输头之外的路由头以及 TNEF 编码的数据不会被保留。

load_from_eml() 是否线程安全?

每次调用 load_from_eml() 都会创建一个独立的 mapi_message 实例。只要每个线程使用自己的消息对象,就可以在多个线程中同时调用它。

另请参阅

 中文