How to Convert EML to MSG in C++

How to Convert EML to MSG in C++

Aspose.Email FOSS for C++ supports bidirectional conversion between EML (RFC 5322 / MIME) and MSG (Outlook MAPI) formats. Use mapi_message::load_from_eml() to import an EML file, then mapi_message::save() to write it as MSG — and vice versa with mapi_message::from_file() followed by mapi_message::save_to_eml().

Step 1 — Set Up the Project

git clone https://github.com/aspose-email-foss/Aspose.Email-FOSS-for-Cpp.git
add_subdirectory(Aspose.Email-FOSS-for-Cpp)
target_link_libraries(your_target PRIVATE AsposeEmailFoss::AsposeEmailFoss)

Step 2 — Convert EML to MSG (File Path)

mapi_message::load_from_eml() parses the EML file and exposes its properties through the standard mapi_message interface. Call save() to write the result as 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";
}

Step 3 — Convert EML to MSG (Stream)

Use the stream overload of load_from_eml() when the EML data comes from a network socket, memory buffer, or another std::istream:

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

Step 4 — Convert MSG to EML

Load an existing MSG file with mapi_message::from_file(), then serialize to EML format with save_to_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";
}

Step 5 — Full Round-Trip (EML → MSG → EML)

The following example demonstrates that subject, body, sender, recipients, and attachments are all preserved through a complete round-trip:

#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';
}

Step 6 — Convert to EML Bytes In Memory

Both save() and save_to_eml() have zero-argument overloads that return std::vector<std::uint8_t>, useful for streaming results to a network connection or database without touching the filesystem:

#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();
}

Common Issues and Fixes

load_from_eml() throws on a valid-looking EML file. Verify the file uses RFC 5322 CRLF line endings. EML files exported by some tools may use bare LF. The library expects standards-compliant line endings.

Missing attachments after EML → MSG conversion. Confirm the EML contains standard MIME multipart/mixed or multipart/related attachment parts. Inline images referenced via cid: are carried as attachments in the MSG and should be present.

HTML body lost after MSG → EML. HTML content is preserved through the round-trip when message.html_body() is non-empty. If only message.body() is populated in the source MSG, the EML will contain only a plain-text part.

save_to_eml() stream output is empty. Open output streams with std::ios::binary. Text-mode streams corrupt the MIME structure on Windows.

Subject contains ?= encoding artefacts. These are RFC 2047 encoded-word sequences in the original EML. The library preserves them as-is. Decode with an RFC 2047 library if you need the plain Unicode subject.

Frequently Asked Questions

Are attachments preserved in both conversion directions?

Yes. Both EML → MSG and MSG → EML conversions carry all MIME attachments through the mapi_message attachment list. Binary attachments are represented as raw bytes in mapi_attachment::data.

Does EML → MSG preserve the HTML body?

Yes. If the EML contains a text/html MIME part, it is stored in the MAPI HTML body property and returned by message.html_body() after loading.

Can I batch-convert a directory of EML files?

Yes. Iterate the directory with std::filesystem::directory_iterator and call mapi_message::load_from_eml() on each .eml path, then save with 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);
        }
    }
}

What is preserved during EML ↔ MSG conversion?

Subject, plain-text body, HTML body, sender name and email address, recipient list, and all MIME attachments. IMAP flags, routing headers beyond basic transport headers, and TNEF-encoded data are not preserved.

Is load_from_eml() thread-safe?

Each call to load_from_eml() creates an independent mapi_message instance. You can call it from multiple threads simultaneously as long as each thread uses its own message object.

See Also