How to Work with Attachments in C++
Aspose.Email FOSS for C++ provides the mapi_attachment class for creating attachments
from raw bytes or streams, and the mapi_message attachment list for reading attachments
from existing MSG files. You can add attachments when composing messages and inspect them
when loading files, including detecting whether an attachment is itself an embedded
MSG message.
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 — Add a File Attachment from Bytes
Use mapi_message::add_attachment() to attach binary data when composing a message.
Provide the filename, the raw bytes as a std::vector<std::uint8_t>, and the MIME
content type:
#include <filesystem>
#include <vector>
#include "aspose/email/foss/msg/mapi_message.hpp"
int main()
{
auto message = aspose::email::foss::msg::mapi_message::create(
"Report", "Please review the attached report.");
message.set_sender_name("Alice");
message.set_sender_email_address("alice@example.com");
message.add_recipient("bob@example.com", "Bob");
// Attach a text file
std::vector<std::uint8_t> text_data{'H', 'e', 'l', 'l', 'o'};
message.add_attachment("notes.txt", text_data, "text/plain");
// Attach a binary blob
std::vector<std::uint8_t> bin_data{0x00, 0x01, 0x02, 0x03};
message.add_attachment("data.bin", bin_data, "application/octet-stream");
message.save(std::filesystem::path("report.msg"));
}Step 3 — Add an Attachment from a File on Disk
Read the file into a byte vector, then pass it to add_attachment():
#include <filesystem>
#include <fstream>
#include <iterator>
#include <vector>
#include "aspose/email/foss/msg/mapi_message.hpp"
int main()
{
// Read a file into bytes
std::ifstream file("document.pdf", std::ios::binary);
std::vector<std::uint8_t> pdf_bytes(
std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>{});
auto message = aspose::email::foss::msg::mapi_message::create(
"Document", "See attached PDF.");
message.set_sender_name("Alice");
message.set_sender_email_address("alice@example.com");
message.add_recipient("bob@example.com", "Bob");
message.add_attachment("document.pdf", pdf_bytes, "application/pdf");
message.save(std::filesystem::path("with_pdf.msg"));
}Step 4 — Read Attachments from an Existing MSG File
message.attachments() returns a const reference to a vector of attachment objects.
Each exposes filename, mime_type, data (the raw bytes), and content_id:
#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 << "Attachments: " << message.attachments().size() << '\n';
for (std::size_t i = 0; i < message.attachments().size(); ++i)
{
const auto& a = message.attachments()[i];
std::cout << "[" << (i + 1) << "]"
<< " name=" << a.filename
<< " mime=" << a.mime_type
<< " bytes=" << a.data.size()
<< " content_id=" << a.content_id
<< '\n';
}
}Step 5 — Detect and Access Embedded Messages
Some MSG files contain other MSG files as attachments (forwarded or meeting invitations).
Use is_embedded_message() to detect these and access the nested message through
embedded_message:
#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);
for (const auto& attachment : message.attachments())
{
if (attachment.is_embedded_message() && attachment.embedded_message != nullptr)
{
const auto& inner = *attachment.embedded_message;
std::cout << "Embedded subject: " << inner.subject() << '\n';
std::cout << "Embedded from: " << inner.sender_email_address() << '\n';
// Save the embedded message as a standalone MSG
inner.save(std::filesystem::path("embedded.msg"));
}
else
{
std::cout << "Regular attachment: " << attachment.filename
<< " (" << attachment.data.size() << " bytes)\n";
}
}
}Step 6 — Save Attachment Data to Disk
Extract attachment bytes and write them to a file using standard C++ file streams:
#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"));
const std::filesystem::path out_dir("attachments");
std::filesystem::create_directories(out_dir);
for (const auto& a : message.attachments())
{
if (!a.is_embedded_message())
{
const auto out_path = out_dir / a.filename;
std::ofstream out(out_path, std::ios::binary);
out.write(reinterpret_cast<const char*>(a.data.data()),
static_cast<std::streamsize>(a.data.size()));
std::cout << "Saved: " << out_path << '\n';
}
}
}Common Issues and Fixes
attachment.data is empty for a known-large attachment. Verify the source MSG file
actually contains the attachment data (not an OLE link). MSG files exported from some
mail clients may store attachments as external references that the library cannot follow.
is_embedded_message() returns true but embedded_message is nullptr. The
attachment header indicates an embedded MSG, but the data was not parseable. Check that
the source MSG is valid and not truncated.
Saving extracted attachment fails with a path error. Some attachment filenames
contain characters that are invalid on the target file system (e.g., :, ? on
Windows). Sanitise attachment.filename before constructing the output path.
Large MSG files cause high memory usage. mapi_message::from_file() loads all
attachment data into memory. For large files, open the underlying CFB container with
cfb_reader to access individual streams without fully materialising all attachments.
add_attachment() not found at compile time. Ensure you are using the correct
include: "aspose/email/foss/msg/mapi_message.hpp". The method is a member of
aspose::email::foss::msg::mapi_message.
Frequently Asked Questions
What MIME types should I use for attachments?
Use the standard IANA MIME type for the file format: "text/plain" for .txt,
"application/pdf" for .pdf, "application/octet-stream" as a generic fallback for
binary files. The MIME type is stored as the attach_mime_tag MAPI property.
Can I attach the same file multiple times?
Yes. Each call to add_attachment() appends an independent attachment entry. Duplicate
filenames are permitted; they are distinguished by position in the attachment list.
How do I set the Content-ID for inline images?
Pass the content ID string as the fourth argument to mapi_attachment::from_stream():
auto att = aspose::email::foss::msg::mapi_attachment::from_bytes(
"logo.png", png_bytes, "image/png", "<logo-cid@example.com>");content_id is exposed as attachment.content_id when reading back.
Is attachment.data a copy or a reference?
attachment.data is a std::vector<std::uint8_t> stored by value inside the
mapi_message object. Accessing it does not trigger additional I/O.
Can I remove an attachment before saving?
The mapi_message API does not expose a direct remove-attachment method in version
0.1.0. Build a new message, copy the desired properties and attachments manually,
and save the new object.