Search code examples
c#asp.netemailemail-attachmentsmemorystream

ASP.NET download email attachment through the MemoryStream failure


On the server side, I have a file containing an XML serialization of a standard System.Net.Mail.MailMessage which may contain attachments. I designed a form to allow users to download these attachments.

Attachment download is controlled by the following code:

private byte[] ReadFully(Stream input)
{
    byte[] _buffer = new byte[16 * 1024];

    using (MemoryStream _ms = new MemoryStream())
    {
        int _read;

        while ((_read = input.Read(_buffer, 0, _buffer.Length)) > 0)
        {
            _ms.Write(_buffer, 0, _read);
        }

        return _ms.ToArray();
    }
}


protected void bntViewAttachment_Click(object sender, EventArgs e)
{
    string _filename = Request.QueryString["file"];

    if (!string.IsNullOrWhiteSpace(_filename))
    {
        MailMessage _message = MailMessageSerializer.Create(Path.Combine(Path.GetFullPath(Path.Combine(Server.MapPath("~"), OUTBOUND_FOLDER)), _filename));

        try
        {

            int _selected = lbAttachments.SelectedIndex;

            if (_selected != -1)
            {
                Attachment _attachment = _message.Attachments[_selected];

                byte[] _data = ReadFully(_attachment.ContentStream);

                if (_data.Length > 0)
                {
                    Response.Clear();
                    Response.ContentType = MimeMapping.GetMimeMapping(_attachment.Name);
                    Response.AddHeader("Content-Disposition", string.Format("attachment;  filename={0}", _attachment.Name));
                    Response.BinaryWrite(_data);
                    Response.End();
                }
                else
                {
                    lblStatus.Text = "Attachment empty";
                }
            }
        }
        catch (Exception ex)
        {
            lblStatus.Text = "Exception : " + ex.Message;
        }
    }
}

The email message file is provided by Request.QueryString["file"]. Of course, this is not the safest way to operate, but right now I have a bigger problem since the download doesn't work at all... since _data.Length == 0 all the time. lbAttachments is the ListBox showing on the form attachments found inside the mail message.

I can attach an example message XML with a single attachment file here.

I'm pretty sure about almost any line of the code since I used them in many other cases, but for some reason it does not here.

Where's the error?


Solution

  • For some reason, the position on the ContentStream must be reset on to its origin.

    Adding

    input.Seek(0, SeekOrigin.Begin);
    

    on top of

    private byte[] ReadFully(Stream input)
    

    Will fix it.

    Now the problem is probably the encoding of the stream write on the client. At first glance, it looks like the exact attachment data that's contained inside the original mail XML file (and thus Base64 or something like that).