views:

1007

answers:

1

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.

+2  A: 

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
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 creationSend messageif(ms != null) Do cleanupThanks for your help.
Chris L