Zip a MemoryStream for an email attachment

11,152

Solution 1

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.

Solution 2

I know this is an old question, but it turned up when I was searching for the same.

Here is my solution to add a compressed (zip) attachment using System.IO.Compression.ZipArchive (requires .NET 4.5 or higher) [based on the answer of acraig5075]:

byte[] report = GetSomeReportAsByteArray();
string fileName = "file.txt";

using (MemoryStream memoryStream = new MemoryStream())
{
    using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Update))
    {
        ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(fileName);
        using (StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open()))
        {
            streamWriter.Write(Encoding.Default.GetString(report));
        }
    }

    MemoryStream attachmentStream = new MemoryStream(memoryStream.ToArray());

    Attachment attachment = new Attachment(attachmentStream, fileName + ".zip", MediaTypeNames.Application.Zip);
    mail.Attachments.Add(attachment);
}

Solution 3

For future reference, the alternate GZipStream method suggested in the accepted answer, to produce a .gz archive is achieved by changing the above code as follows.

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

    var outStream = new MemoryStream();
    using (var compress = new GZipStream(outStream, CompressionMode.Compress))
    {
        inStream.CopyTo(compress);
        compress.Close();
    }

    var ms = new MemoryStream(outStream.ToArray());
    Attachment attachment = new Attachment(ms, "report.xml.gz", "application/gzip");
    return attachment;
}

The using block and the ToArray() call are required.

Share:
11,152
acraig5075
Author by

acraig5075

Capetownian, software developer, land surveyor.

Updated on June 04, 2022

Comments

  • acraig5075
    acraig5075 about 2 years

    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?