7

Our project has files stored in a sql server db as blobs. I'd like to get the files from the database and attach multiple files to an email without writing to disk.

This is what I have so far(everything works ok, with no attachments):

// snip

List<System.Net.Mail.Attachment> attachments = null;
// Attachments is a child list of Messagebody object holding Attachment ids
MessageBody.Attachments = MessageBodyAttachmentList.GetMessageBodyAttachmentList(this.MessageBody.ID);

if (MessageBody.Attachments != null && MessageBody.Attachments.Count > 0)
{
    attachments = new List<Attachment>();

    foreach (Library.Entity.Messaging.MessageBodyAttachment att in MessageBody.Attachments)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            // create a new attachment
            Library.Attachments.Attachment attachment = Library.Attachments.Attachment.GetAttachment(att.AttachmentID);

            byte[] contentAsBytes = attachment.FileData;// FileData holds byte[] that is the contents of the file
            memoryStream.Write(contentAsBytes, 0, contentAsBytes.Length);
            memoryStream.Seek(0, SeekOrigin.Begin);

            // content type for file info
            ContentType contentType = new ContentType();
            contentType.MediaType = MediaTypeNames.Application.Octet;
            contentType.Name = attachment.FileName;

            // create the .Net specific attachment
            Attachment netAttachment = new Attachment(memoryStream, contentType);
            attachments.Add(netAttachment);

            memoryStream.Position = 0;
        }
    }
}

response = message.SendMessage(_recipient, _sender, _cc, _bcc, MessageBody.Subject, MessageBody.Body, true, attachments);
// snip

public string SendMessage(string to, string from, string cc, string bcc, string subject, string body, bool IsHtml,  List<Attachment> attachments)
{
    string response = String.Empty;
    System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage(from, to, subject, body);

    // Add the attachments
    if (attachments != null)
    {
        foreach (Attachment a in attachments)
            message.Attachments.Add(a);
    }

    message.IsBodyHtml = IsHtml;

    if (IsHtml)
    {
        // snip
    }

    try
    {
        _client.Timeout = 500000;
        _client.Send(message);
    }
    catch (SmtpException smtpex)
    {
        response = smtpex.Message;
    }
    catch (System.Exception ex)
    {
        response = ex.Message;
    }
    return response;
}

I'm getting the following errors:

exception message: Failure sending mail.
source: System
stack trace:
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at MyCompany.Shared.Email.SMTPMessage.SendMessage(String to, String from, String cc, String bcc, String subject, String body, Boolean IsHtml, List`1 attachments) in C:\svn_repos\branches\2010.02.28\Net\Common\Shared\Email\SMTPMessage.cs:line 116

inner exception msg: Cannot access a closed Stream.
inner source: mscorlib
inner targetsite: {Void StreamIsClosed()}
inner stack trace:
   at System.IO.__Error.StreamIsClosed()
   at System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.Mime.MimePart.Send(BaseWriter writer)
   at System.Net.Mime.MimeMultiPart.Send(BaseWriter writer)
   at System.Net.Mail.Message.Send(BaseWriter writer, Boolean sendEnvelope)
   at System.Net.Mail.MailMessage.Send(BaseWriter writer, Boolean sendEnvelope)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)

I copied most of the stream code from examples I found on the web.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Chris L
  • 669
  • 2
  • 10
  • 21
  • 1. don't use tabs (use spaces), makes it easier to fix formatting for web, and 2. to post code on Stack Overflow, indent each line by 4 spaces (you can select the code afterwards and hit Ctrl+K or use the toolbar button) – Lasse V. Karlsen Jan 29 '10 at 23:28

1 Answers1

11

You've found a reason to not implement a using block: when you're still going to use the object after the block has exited. Take the MemoryStream out of the using block.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • 1
    Your're right, the using block was causing the problems. I redid it to something like this: memorystream ms = null; if(I have attachments) ms = new memorystream() Do attachment creation Send message if(ms != null) Do cleanup Thanks for your help. – Chris L Feb 01 '10 at 15:39
  • 2
    How did you use the memory stream to handle multiple attachments? I've created 1 per and manually disposed of them but I wanted to see if there was a better way, and also to make sure I don't create any memory leaks - thx – Mad Halfling Sep 06 '11 at 10:16
  • I have the same question. – Kate Nov 13 '13 at 12:35
  • @Mad Halfling & Kate: I just added a List within the class, used SmtpClient.SendAsync() to send the message, then in SmtpClient.SendCompleted even process the List with Close() and Dispose() of each one. – AdvApp Jan 11 '16 at 20:16
  • According to this http://stackoverflow.com/questions/8477769/why-do-i-need-to-dispose-a-system-net-mail-mailmessage-instance#8477820, disposing the `MailMessage` is enough to dispose the attached streams. – youen Feb 03 '17 at 14:08