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.gitadd_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.