1

I cannot use using inside the loop because then I won't be able to send email because cannot access a closed stream.

I cannot using(MemoryStream memoryStream = new MemoryStream()){the rest of the codes} because then only first excel will have data, the rest will be empty with file size of 64 B. I already verify that all excel have data before send it via email.

foreach (workbook excel in workbooks)
{
    MemoryStream memoryStream = new MemoryStream();
    excel.hssfWorkBook.Write(memoryStream);
    memoryStream.Position = 0;
    mailMessage.Attachments.Add(new Attachment(memoryStream, excel.fileName, "application/vnd.ms-excel"));
}
smtpClient.Send(mailMessage);
Pop
  • 525
  • 1
  • 7
  • 22
  • 1
    Disposing the memory stream only prevents future read/writes (which you *don't* want - you want the email library to read from the stream). Disposing the stream does not cause the memory to be cleaned up any faster. As far as I can see, your code is correct. However, you could add the streams to a list as you create them, and then dispose each one after `Send`, if you wish. See [this](http://stackoverflow.com/a/234257/563532) for more information – Rob Aug 19 '16 at 02:54
  • 2
    I wouldn't sweat it. MemoryStream does not actually have any unmanaged resources to dispose of, so letting the GC handle it without closing or disposing it is fine. Note that this is an exception to best practice with IDisposables, though. – Glorin Oakenfoot Aug 19 '16 at 02:54
  • 1
    MemoryStream is not really a problem since as mentioned above it has no unmanaged resources. However if you did have some other streams, just dispose the `MailMessage` object after it is sent. It should dispose all the attachments and their underlying streams. – Mike Zboray Aug 19 '16 at 02:59

1 Answers1

2

There is no need to close this memory stream.

You just need to make sure your mailMessage is disposed properly. Once it is disposed, all attachments are disposed as well, and therefore their Streams.

Look at MailMessage source code here and search Dispose() implementation:

public void Dispose()
{
    Dispose(true);
}

protected virtual void Dispose(bool disposing)
{
    if (disposing && !disposed)
    {
        disposed = true;

        if(views != null){
            views.Dispose();
        }
        if(attachments != null){
            attachments.Dispose();
        }
        if(bodyView != null){
            bodyView.Dispose();
        }
    }
}

To dispose your mailMessage, just use using like this simple example:

using (var mailMessage = new MailMessage())
{
    using (var smtpClient = new SmtpClient())
    {
        foreach (workbook excel in workbooks)
        {
            MemoryStream memoryStream = new MemoryStream();
            excel.hssfWorkBook.Write(memoryStream);
            memoryStream.Position = 0;
            mailMessage.Attachments.Add(new Attachment(memoryStream, excel.fileName, "application/vnd.ms-excel"));
        }
        smtpClient.Send(mailMessage);
    }
}
Rob
  • 26,989
  • 16
  • 82
  • 98
Alisson Reinaldo Silva
  • 10,009
  • 5
  • 65
  • 83