You can attach a file to an Outlook MSG message straight from disk or from an open stream. You no longer need to read the whole file into memory first. This guide shows both options, explains who is responsible for closing the stream, and shows how to read attachments back the same way.
Why add large attachments with stream support
When you attach a file as a byte array, the whole file has to be in memory first. That uses a lot of memory for big files, and a .NET byte array cannot hold more than about 2.1 GB, so larger files cannot be attached that way at all.
When you attach from a file path or a stream instead, Aspose.Email for .NET reads the content only when it needs it: when you save the message or open the attachment. Memory use stays low, and the file size is no longer limited by what fits in a byte array.
You can work with attachments in four ways:
- Attach a file by its path, optionally with a different display name.
- Attach content from a stream you already have open.
- Check an attachment’s size without reading it.
- Open an existing attachment as a read-only stream.
Using Aspose.Email for adding large attachments
Install Aspose.Email for .NET 26.9 or later from NuGet:
Install-Package Aspose.Email
The examples use the Aspose.Email.Mapi and System.IO namespaces.
Attach a large file from its path
If the file is already on disk, pass its path. The message opens the file when it needs the content, so the file is never loaded into memory as a whole.
using (var msg = new MapiMessage("from@domain.com", "to@domain.com", "Quarterly report", "See the archive attached."))
{
msg.Attachments.AddFile(@"C:\data\archive.zip");
msg.Save(@"C:\out\report.msg");
}
After the code runs, report.msg contains the ZIP archive as an attachment named archive.zip. To show a different name in the email client, pass it as a second argument.
Keep the using block. When you attach by path, the message holds the file open until it is disposed. If you skip that step, the file stays locked.
Attach a large file from a stream
If you already have the content as a stream, for example a file you opened for another purpose, attach the stream directly and give the attachment a name.
using (var content = File.OpenRead(@"C:\data\presentation.pptx"))
{
var msg = new MapiMessage("from@domain.com", "to@domain.com", "Slides", "Slides attached.");
var attachment = msg.Attachments.Add("presentation.pptx", content);
Console.WriteLine($"Attachment size: {attachment.ContentLength} bytes");
msg.Save(@"C:\out\slides.msg");
}
The console shows the size of the presentation, and slides.msg contains the full file. Because the new attachment is returned to you, you can check its size straight away without reading the content.
What the stream needs
The stream has to meet three conditions:
- It must support reading and seeking. Aspose.Email checks the length and may read the content more than once while saving. If the stream does not qualify, you get an error as soon as you attach it, not later when you save.
- Content is taken from the current position to the end. If you have already read part of the stream, move back to the start before you attach it.
- It must stay open until you save. The content is read on demand, so closing the stream early breaks the save.
If your source cannot seek, such as a download from the web, copy it into a seekable stream first:
using (var buffer = new MemoryStream())
{
responseStream.CopyTo(buffer);
buffer.Position = 0;
msg.Attachments.Add("download.bin", buffer);
}
Keep in mind that a memory stream holds the whole file in memory. For very large downloads, save the content to a temporary file and attach that file instead.
Who closes the stream
By default, the stream stays yours. You close it after the message is saved, as the using block does in the example above.
If you would rather hand the stream to the message, pass false as a third argument. The message then closes the stream when the message itself is disposed, so make sure you dispose the message. The same applies when you attach a file by its path.
Read attachments back as streams
You can also go the other way: open an attachment in an existing message as a read-only stream and copy it to disk, without creating an in-memory copy.
var msg = MapiMessage.Load(@"C:\data\message.msg");
foreach (MapiAttachment attachment in msg.Attachments)
{
Console.WriteLine($"{attachment.LongFileName}: {attachment.ContentLength} bytes");
using (Stream source = attachment.OpenRead())
using (Stream target = File.Create(Path.Combine(@"C:\out", attachment.LongFileName)))
{
source.CopyTo(target);
}
}
The console lists each attachment with its size, and each file is saved to C:\out. Each stream you open is independent, so reading one attachment does not affect another.
Next steps
See the attachment methods in the API reference for the full parameter details, and the Aspose.Email for .NET documentation for other attachment tasks. If you run into a problem, ask on the Aspose.Email support forum.
FAQs
Why attach from a stream or file path instead of a byte array? A byte array holds the whole file in memory before you attach it, and it cannot hold more than about 2.1 GB. Attaching from a stream or a file path lets Aspose.Email read the content only when it needs it, such as when you save the message.
Does Aspose.Email close the stream I pass in? Not by default. You keep ownership and must leave the stream open until the message is saved. If you want the message to close it for you, pass
falsefor theleaveStreamOpenargument and dispose the message when you are done.Can I attach a stream that does not support seeking, such as a network stream? No. The stream must support both reading and seeking. Copy the content into a seekable stream first.
Can I find out an attachment’s size without reading it? Yes. Each attachment reports its size in bytes through the
ContentLengthproperty, without reading the content.How do I save an attachment to disk without loading it into memory? Open the attachment as a read-only stream with
OpenReadand copy that stream to a file.
Get a Free License and Explore More
Request a free temporary license to test Aspose.Email for .NET without evaluation restrictions.
