读取 MSG 文件

读取 MSG 文件

mapi_message 是加载和解析 Outlook MSG 文件的入口点。一次调用 from_file() 或 from_stream() 即可读取完整的 CFB 容器,提取所有 MAPI 属性,并通过类型化的访问器方法公开——无需安装 Outlook。


从文件路径加载

使用 mapi_message::from_file() 与 std::filesystem::path:

#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"));

    std::cout << "Subject: " << message.subject() << '\n';
    std::cout << "From:    " << message.sender_name()
              << " <" << message.sender_email_address() << ">\n";
    std::cout << "Body:    " << message.body() << '\n';
}

从流加载

当 MSG 数据来自网络套接字、归档文件或任何 std::istream 时,使用 mapi_message::from_stream():

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

int main()
{
    std::ifstream input("sample.msg", std::ios::binary);
    const auto message = aspose::email::foss::msg::mapi_message::from_stream(input);

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

始终使用 std::ios::binary 打开流。文本模式的流在 Windows 上会转换换行符,从而损坏 CFB 容器。


访问消息属性

mapi_message 将最常用的消息属性公开为具名 getter:

#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"));

    // Core properties
    std::cout << "Subject:          " << message.subject() << '\n';
    std::cout << "Sender name:      " << message.sender_name() << '\n';
    std::cout << "Sender email:     " << message.sender_email_address() << '\n';
    std::cout << "Internet msg-id:  " << message.internet_message_id() << '\n';
    std::cout << "Message class:    " << message.message_class() << '\n';

    // Body — check html_body() first; fall back to plain body()
    const auto& body = message.html_body().empty()
        ? message.body()
        : message.html_body();
    std::cout << "Body length: " << body.size() << " chars\n";
}

遍历收件人

message.recipients() 返回一个 std::vector,其中包含收件人对象,具备 display_name、email_address 和 recipient_type:

#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"));

    for (std::size_t i = 0; i < message.recipients().size(); ++i)
    {
        const auto& r = message.recipients()[i];
        std::cout << "[" << (i + 1) << "] "
                  << r.display_name << " <" << r.email_address << ">"
                  << "  type=" << r.recipient_type << '\n';
    }
}

遍历附件

message.attachments() 返回一个 std::vector,其中包含附件对象。每个对象公开 filename、mime_type、data、content_id 和 is_embedded_message():

#include <filesystem>
#include <fstream>
#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"));

    for (const auto& a : message.attachments())
    {
        std::cout << a.filename
                  << "  " << a.mime_type
                  << "  " << a.data.size() << " bytes"
                  << "  embedded=" << (a.is_embedded_message() ? "yes" : "no")
                  << '\n';

        if (!a.is_embedded_message())
        {
            std::ofstream out("extracted_" + a.filename, std::ios::binary);
            out.write(reinterpret_cast<const char*>(a.data.data()),
                      static_cast<std::streamsize>(a.data.size()));
        }
    }
}

访问嵌入式消息

当 is_embedded_message() 为 true 时,附件包含另一个 MSG 文件。通过 attachment.embedded_message 访问它:

#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"));

    for (const auto& a : message.attachments())
    {
        if (a.is_embedded_message() && a.embedded_message != nullptr)
        {
            const auto& inner = *a.embedded_message;
            std::cout << "Embedded subject: " << inner.subject() << '\n';
            inner.save(std::filesystem::path("embedded.msg"));
        }
    }
}

提示与最佳实践

  • 加载 MSG 文件时,始终将 std::ios::binary 传递给 std::ifstream。
  • 在 body() 之前检查 html_body() —— HTML 专用的消息将其内容存储在 HTML body 属性中,并将 body() 留空。
  • from_file() 将所有附件数据加载到内存中。对于大型 MSG 文件,考虑使用 msg_reader 打开底层容器,以在不完全实例化附件字节的情况下检查元数据。
  • from_file(path, strict) 和 from_stream(stream, strict) 的 strict 参数默认值为 false,能够容忍实际 MSG 文件中轻微的结构偏差。
  • 收件人对象公开 recipient_type 用于区分 To、Cc 和 Bcc 条目。

常见问题

问题原因修复
对看起来有效的文件执行msg_exception文件不是合法的 OLE CFB 容器使用cfb_reader::from_file()进行验证 — 如果它也抛出异常,则文件不是有效的 MSG
body() 返回空字符串消息仅使用 HTML 正文使用 html_body() 替代
recipients() 为空较旧的 MSG 没有收件人表通过 get_property_value() 使用 common_message_property_id::display_to 访问 display_to
Windows 上的流损坏流在未使用 std::ios::binary 的情况下打开向 std::ifstream 添加 std::ios::binary 标志
大文件的高内存使用所有附件数据在一开始就已加载使用 msg_reader 进行低级访问,而无需完整实例化

FAQ

from_file() 会保持文件句柄打开吗?

不。文件在打开后被完整解析,并在方法返回前关闭。调用后可以移动或删除源文件。

我如何判断附件是普通文件还是嵌入的 MSG?

调用 attachment.is_embedded_message()。对嵌入的 MSG 文件返回 true;对常规文件附件返回 false。对于嵌入的消息,可通过 attachment.embedded_message 访问嵌套对象。

from_file() 与使用 msg_reader 有何区别?

mapi_message::from_file() 是高级 API——它解析完整消息并将属性以强类型字段公开。msg_reader 是低级读取器,提供对原始 CFB 容器结构的访问,当您需要在不解析所有 MAPI 属性的情况下检查消息布局时非常有用。

是否同时支持 Unicode 和 ANSI 的 MSG 文件?

是的。mapi_message 同时处理 Unicode(属性类型 ptyp_string)和 ANSI(ptyp_string8)字符串属性。unicode_strings() 对使用 Unicode 属性存储的消息返回 true。


API Reference 摘要

类 / 方法描述
mapi_message::from_file(path)从 std::filesystem::path 加载 MSG 文件
mapi_message::from_file(path, strict)加载时使用严格模式选项
mapi_message::from_stream(stream)从 std::istream 加载 MSG
mapi_message::from_stream(stream, strict)使用严格模式选项从流加载
mapi_message::subject()返回消息主题字符串
mapi_message::body()返回纯文本正文
mapi_message::html_body()返回 HTML 正文(如果不存在则为空)
mapi_message::sender_name()返回发件人的显示名称
mapi_message::sender_email_address()返回发件人的电子邮件地址
mapi_message::internet_message_id()返回 RFC 2822 Message-ID 头部
mapi_message::message_class()返回 MAPI 消息类字符串
mapi_message::recipients()返回收件人列表
mapi_message::attachments()返回附件列表
mapi_attachment::is_embedded_message()如果附件是嵌入式 MSG,则为 True
mapi_message::unicode_strings()如果消息使用 Unicode 字符串属性,则为 True

另请参阅

 中文