Search code examples
.netzipattachmentdeflatestream

Zip a MemoryStream for an email attachment


I'm trying to zip an XML tree and use it as an email attachment. The sending of the email with an attachment succeeds, but the zip file created is always corrupt – it is not a valid zip file but does contain binary data.

The problem is recreated as follows, see specifically BuildAttachment():

static void Main(string[] args)
{
    try
    {
        var report = new XElement("Report",
            new XElement("Product",
                new XElement("ID", "10000001"),
                new XElement("Name", "abcdefghijklm"),
                new XElement("Group", "nopqrstuvwxyz")
            )
        );
        var mailMessage = BuildMessage(report);
        EmailMessage(mailMessage);
        Thread.Sleep(10000);
    }
    catch (Exception e) { Console.WriteLine(e.Message); }
}
static MailMessage BuildMessage(XElement report)
{
    string from = "[email protected]";
    string to = "[email protected]";
    var message = new MailMessage(from, to, "Subject text", "Body text");

    var attachment = BuildAttachment(report);
    message.Attachments.Add(attachment);

    return message;
}
static Attachment BuildAttachment(XElement report)
{
    var inStream = new MemoryStream();
    report.Save(inStream);
    inStream.Position = 0;

    var outStream = new MemoryStream();
    var compress = new DeflateStream(outStream, CompressionMode.Compress);
    inStream.CopyTo(compress);

    outStream.Position = 0;
    return new Attachment(outStream, "report.zip", "application/zip");
}
static void EmailMessage(MailMessage message)
{
    var smtpClient = new SmtpClient("127.0.0.1");
    smtpClient.SendCompleted += SendCompletedCallback;
    smtpClient.SendAsync(message, null);
}
static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
    if (e.Error != null)
        Console.WriteLine(e.Error.ToString());
}

To put the problem in context: It’s part of a windows service application so I don’t want to create files on disk, and the email message also contains xslt-transformed alternate views of the xml tree so I don’t want a completely different solution.

Any suggestions why the zip file is corrupt?


Solution

  • You're not creating a valid zip file, you're just creating a compressed stream and writing it to a file that has a *.zip extension. You should use a .NET zip library instead of DeflateStream.

    You can use something like DotNetZip Library:

    DotNetZip is an easy-to-use, FAST, FREE class library and toolset for manipulating zip files or folders. Zip and Unzip is easy: with DotNetZip, .NET applications written in VB, C# - any .NET language - can easily create, read, extract, or update zip files. For Mono or MS .NET.

    If you have constraints and cannot use an external library, you could try to use GZipStream and add the attachment with an extension of *.gz which would be supported by common compression tools.

    As useful information for future reference, .NET 4.5 will finally introduce native support for zip archiving through the ZipArchive class.