Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attaching Multiple Files To An E-Mail From Database Image Column In .NET

are there any good examples of how to attach multiple files from a database to an e-mail in .NET? I've got a method that returns a Byte[] containing the Image column contents that I am calling in a loop to get each attachment, but I was wondering if there was a "correct"/best-practice way of doing this, especially with the possibility of introducing memory leaks by using MemoryStreams to contain the data? I'm fine creating en e-mail object and attaching the list of attachments to it, once I've got them and can do this fine with a single attachement but it seems to get slightly more complex with multiple files. Considering I wouldn't have thought this was an unusual requirement, there seems to be a dearth of articles/posts about it.

Thx - MH

like image 288
Mad Halfling Avatar asked Jan 18 '23 19:01

Mad Halfling


2 Answers

Here's how to proceed. Let's suppose that you have an array of attachments that you have loaded from your database:

IEnumerable<byte[]> attachments = ... fetch from your database

We could also safely assume that along with those attachments you have loaded the filenames and probably their corresponding MIME type (information that you surely must have persisted along with those byte arrays representing your attachments). So you will probably have fetched IEnumerable<SomeAttachmentType> but that's not important for the purpose of this post.

So now you could send the mail:

using (var client = new SmtpClient("smtp.foo.com"))
using (var message = new MailMessage("[email protected]", "[email protected]"))
{
    message.Subject = "test subject";
    message.Body = "test body";
    message.IsBodyHtml = false;
    foreach (var attachment in attachments)
    {
        var attachmentStream = new MemoryStream(attachment);
        // TODO: Choose a better name for your attachments and adapt the MIME type
        var messageAttachment = new Attachment(attachmentStream, Guid.NewGuid().ToString(), "application/octet-stream");
        message.Attachments.Add(messageAttachment);
    }
    client.Send(message);
}

Here's the deal:

A MailMessage (IDisposable) contains multiple Attachments (IDisposable). Each attachment references a MemoryStream (IDisposable). The MailMessage is wrapped in a using block which ensures that its Dispose method will be called which in turn calls the Dispose method of all attachments which in turn call the Dispose method of the memory streams.

like image 95
Darin Dimitrov Avatar answered Jan 21 '23 08:01

Darin Dimitrov


Hi you can have buffered reads directly from the database, MemoryStream does NOT introduce any memory leak if you dispose it after usage. Example using SqlDataReader:

using(var stream = new MemoryStream())
{
  byte[] buffer = new byte[4096];

  long l, dataOffset = 0;
  while ((l = reader.GetBytes(columnIndex, dataOffset, buffer, 0, buffer.Length)) > 0)
  {
      stream.Write(buffer, 0, buffer.Length);
      dataOffset += l;
  }

  // here you have the whole stream and can attach it to the email...
}

similar question on how to read bytes from database has been asked already countless times, see here for example: What is the most efficient way to read many bytes from SQL Server using SqlDataReader (C#)

like image 37
Davide Piras Avatar answered Jan 21 '23 08:01

Davide Piras