Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream closed error when adding attachment to MailMessage

Tags:

c#

.net

email

I use the following code to attach a file to an email message.

msg = new MailMessage();

    using (strMem = new MemoryStream((byte[])attDr["filedata"]))
    {
        using (strWriter = new StreamWriter(strMem))
        {
            strWriter.Flush(); strMem.Position = 0;
            using (attachment = new Attachment(strMem, attDr["filename"].ToString()))
            {
                msg.Attachments.Add(attachment);
            }
        }
    }

...
...
msg.Send();  //Error: System.ObjectDisposedException: Cannot access a closed Stream.

The error message is: //Error: System.ObjectDisposedException: Cannot access a closed Stream

Im guessing that the "USING" statement closes the stream when exiting the block. But why doesnt "Attacments.Add()" make its own copy of the stream?

like image 753
David Avatar asked Mar 09 '11 21:03

David


2 Answers

The Send() method is going to access the attachments to embed them into the mail message. That goes kaboom here, the memory stream was disposed. You need to move the Send() call inside of the using statements so the stream doesn't get disposed until after the message is sent.

Mentioning that using isn't necessary here because a memory stream doesn't have any unmanaged resources that need to be disposed always gets me into trouble at SO. So I won't bring that up.

like image 155
Hans Passant Avatar answered Sep 20 '22 04:09

Hans Passant


One solution I found to this when I was dealing with a scenario where the MailMessage was being created separate from the sending and potentially with multiple attachments was to use a List of MemoryStream objects

// Tuple contains displayName and byte[] content for attachment in this case
List<Tuple<string,byte[]>> attachmentContent;
MailMessage email = BuildNativeEmail(requestObject, out attachmentContent);
List<MemoryStream> streams = new List<MemoryStream>();
foreach(Tuple<string,byte[]> attachment in attachmentContent)
{
    MemoryStream m = new MemoryStream(attachment.Item2);
    email.Attachments.Add(new System.Net.Mail.Attachment(m, attachment.Item1));
    streams.add(m);
}

// client represents a System.Net.Mail.SmtpClient object
client.Send(email);

foreach(MemoryStream stream in streams)
{
    stream.Dispose();
}
like image 16
Lorcan O'Neill Avatar answered Sep 24 '22 04:09

Lorcan O'Neill