Releasing Email File Attachment Resources (System.Net.Mail)

I’ve been looking through the temp directories on my production machines and had realized some overlooked design points in a number of programs; namely the deletion of certain temp files. 

One situation that particularly caught my attention was some email attachments that should have been deleted.
Even though the code was actively calling File.Delete() on some email attachments, they were not being deleted.
An error log showed the program was throwing an exception when attempting to delete the files.
The mail was being delivered successfully with no visible flaws to the customer.

I finally decided to write some test code to reproduce the problem that I originally thought was caused by the ZIP compression step right before the mail send.

The problem actually turned out to be I was not calling Dispose() on the attachment resources after the mail send.  Most Dot Net classes I use don’t require the explicit calling of a Dispose() method, so I completely bypassed this one until it became necessary.  Here’s an example of the solution:
 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mail;

 …

   1:        /// <summary>
   2:        /// Example of simple mailing with attachment and release of attachments.
   3:        /// </summary>
   4:        /// <param name="lst_strAttachments">List&lt;string&gt;
   5:        /// filenames to attach to the email.
   6:        /// </param>
   7:        /// <param name="strError">Output of exception text</param>
   8:        /// <returns>bool: true if no exceptions</returns>
   9:        public static bool SendMail(List<string> lst_strAttachments, ref string strError)
  10:        {
  11:           bool blnRetVal = true;
  12:           try
  13:           {
  14:              string strSubjectBody = "Test Email With Attachment";
  15:   
  16:              // Make a basic mail message
  17:              MailMessage msg = new MailMessage()
  18:              {
  19:                 Subject = strSubjectBody,
  20:                 Body = strSubjectBody,
  21:                 Priority = MailPriority.Low,
  22:                 From = new MailAddress(EMAIL_ADDRESS_TO_FROM)
  23:              };
  24:   
  25:              msg.To.Add(msg.From); //same as from
  26:              //http://msdn.microsoft.com/en-us/library/system.net.mail.attachment.aspx
  27:              lst_strAttachments.ForEach(a => msg.Attachments.Add(new Attachment(a)));
  28:   
  29:              (new SmtpClient(SMTP_SERVER_ADDRESS)).Send(msg);
  30:   
  31:              // Free the attachment resources
  32:              msg.Attachments.ToList().ForEach(a => a.Dispose());
  33:           }
  34:           catch (Exception exc)
  35:           {
  36:              blnRetVal = false;
  37:              strError = exc.Message;
  38:           }
  39:   
  40:           return blnRetVal;
  41:        }

 

…and a small calling program example:
The Zip class is a custom wrapper.

   1:        static void Main(string[] args)
   2:        {
   3:           string strError = "";
   4:           string strTempFileName = CSampleTempFile.MakeSampleTempFile("One.txt");
   5:           string strZipFileName = Path.Combine(Path.GetTempPath(),"Test.zip");
   6:           
   7:           if (!CZipLib.ZipMove(strZipFileName,
   8:              new List<string>{strTempFileName}, //list of files (containing 1)
   9:              ref strError))
  10:           {
  11:              Console.WriteLine("Could not zip file {0:G}\n\t: {1:G}",
  12:                 strTempFileName, strError);
  13:              return;
  14:           }
  15:   
  16:           if (!SendMail(new List<string>{strZipFileName}, ref strError))
  17:           {
  18:              Console.WriteLine("Could not send mail: " + strError);
  19:              return;
  20:           }
  21:   
  22:           File.Delete(strZipFileName); //<--WORKS!
  23:        }

 

posted @ Thursday, July 14, 2011 11:40 AM
Print

Comments on this entry:

# re: Releasing Email File Attachment Resources (System.Net.Mail)

Left by Jim Lawless at 7/17/2011 7:36 AM
Gravatar
Thanks for this, Tom. I've written a C#-based e-mail product for which I am not releasing these resources, either ... but, I will be soon! ;-)

# re: Releasing Email File Attachment Resources (System.Net.Mail)

Left by Matt Burns at 1/28/2013 4:06 AM
Gravatar
That fixed my bug when attempting to clean up a temporary file after emailing it. (file in use by another process blah blah blah)

Cheers!

# re: Releasing Email File Attachment Resources (System.Net.Mail)

Left by Blast_Radius at 4/1/2013 3:02 PM
Gravatar
Thanks, I knew there was something I wasn't closing or disposing.

# re: Releasing Email File Attachment Resources (System.Net.Mail)

Left by Rokib at 8/17/2013 5:56 AM
Gravatar
try
{
MailMessage mail = new MailMessage();
mail.To.Add(To Mail Id);
mail.CC.Add("From Mail Id");

mail.From = new MailAddress("To Mail Id");
mail.Subject = " Invoice.";
string Body = "Mail Msg";

AlternateView htmlView = AlternateView.CreateAlternateViewFromString(Body, null, "text/html");
//displaying logo on the top of mail msg
LinkedResource imagelink = new LinkedResource(Server.MapPath(".") + @"\" + lb_img.Text + "", "image/JPG");

imagelink.ContentId = "imageId";

imagelink.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;

htmlView.LinkedResources.Add(imagelink);

mail.AlternateViews.Add(htmlView);
mail.Body = Body;
Attachment at = new Attachment(Server.MapPath("PDF/" + fileName + ""));
mail.Attachments.Add(at);

SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587);
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential("mail id", "password");

smtp.Send(mail);
// Free the attachment resources
at.Dispose();
}
catch (Exception ex)
{
//Error, could not send the message
Response.Write(ex.Message);
}

Your comment:



(not displayed)

 
 
 
 

Live Comment Preview: