Open File Handles From Mail Attachment

Hi,


I’m experiencing file handles being left open when creating a new MailMessage to send via SMTP and attaching files. I’m attaching them to the MailMessage like so (they are PDFs in this case, I haven’t tested with other files):

===========================
For Each fp As FileRef In mFiles
msg.AddAttachment(New Aspose.Network.Mail.Attachment(fp.Path))
Next

'FileRef is defined as a structure like this:
Public Structure FileRef
Public ID As String
Public Path As String

Public Sub New(ByVal path As String, ByVal id As String)
Me.ID = id
Me.Path = path
End Sub
End Structure

===========================

I went to delete the PDF files (because they are being generated by SQL reporter and Aspose.PDF, 2 separate files) while my application was still running and it told me they could not be deleted because they were in use.

They weren't both created the same way, so I found this as odd behavior. If anything I thought I was closing my Facades.Form object incorrectly, but the SQL reporter PDF (which has no connection to Aspose) was also giving the error message.

I commented out the line that attached my PDF files to the email and let the emails send without any attachments. While the application was still running, I was able to delete the file without any issue.

I am currently using Aspose.Network 6.4.0.0. I see that the namespace has changed to Aspose.Email. Has this issue been addressed or am I doing something incorrectly here? Obviously I can update, but I would like to know if this was fixed in the latest version.

Also, for async sends, do I need to worry about calling Dispose on the MailMessage object (inside the callback) and its attachments at all? I don't see any information about object clean up in the documentation.

Thank you.

An update to my issue here.


I spent time implementing the SendCompleted callback properly to dispose of the MailMessage and SmtpClient objects. I’m almost certain this worked before.

Now as I debug this issue, I noticed my code is not even entering the SendCompleted event (breakpoints are not being hit), however the emails are still being delivered successfully. I’m adding the event handler like so:

AddHandler client.SendCompleted, AddressOf SendCompletedCallback

Private Shared Sub SendCompletedCallback(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
If (e.Error IsNot Nothing) Then
Debug.WriteLine("Transport:SendCompletedCallback Email error: " + e.Error.ToString())
Else
Debug.WriteLine(“Transport:SendCompletedCallback Message sent”)
End If

’ Clean up MailMessage object and its attachments
Dim msg As MailMessage = DirectCast(e.UserState, MailMessage)
If msg IsNot Nothing Then
msg.Dispose()
msg = Nothing
End If

’ Clean up SmtpClient object
If TypeOf sender Is SmtpClient Then
Dim client As SmtpClient = DirectCast(sender, SmtpClient)
If client IsNot Nothing Then
client.Dispose()
client = Nothing
End If
End If
End Sub


I disposed the Attachment after I called AddAttachment just to try something else (I know it fails), and then the code hit the SendCompleted event because the error stated it could not send the email since the attachment was already closed/gone, which makes sense.

Any ideas?

Hi Phil,

Thank you for your inquiry.

I am preparing a sample application for you to test your scenario with real time data before upgrading your actual application. I will attach the sample as soon as it is prepared.

As you may know Aspose.Email.Mail.[MailMessage](http://docs.aspose.com/display/emailnet/MailMessage+Class) implements IDisposable. So according to the general rule, the MailMessage should be declared and instantiated in a using statement. I have tested the latest build on similar lines and I have learned that a file cannot be deleted if it has been added as an attachment and the MailMessage object isn’t disposed yet. As soon as the program control leaves the using block, the file can be deleted.

Regarding the question in your second post, I will get back to you on that.

Right, but you cannot use a using block with SendAsync, correct? The client object is able to go out of scope before it is actually sent.

Hi Phil,


I have forwarded your inquiry to the development team for an expert’s opinion on this matter. I am also investigating it on my end. We will keep you posted with updates in this regard.

Hi Phil,


Thank you for your patience.

Please find attached a sample application for your reference. The archive also contains the .NET 2.0 assembly of Aspose.Email for .NET v1.4.0. I have tested your said scenario by adding several attachments from a pool of files and I was able to delete these files as soon as message was disposed.

Please test the project at your end and feed us back with your results.

Babar,


Thank you for the sample project. After seeing how it works I went and removed my Aspose.Network reference from my project and added Aspose.Email.

What my project is doing is looping over some data set and sending out emails with attachments (like your sample project, but let’s say the SmptSendAsync method gets called again multiple times) when a button is pressed.

The first time I load the app and press the button, the code never enters the callback (whether I sent one email in the loop (ie, n=1 for data) or 50 emails). Then after that is done executing, I can press the button again a second time (and third, and fourth and so on) and the callback gets entered every time.

I should note that this is running in a BackgroundWorker component. I will try and extend your sample project to be in the same situation to see if I experience this at all. Of course, it could be something else within my project as it is rather large and not as simple as the sample application you provided.

Let me know if you have any other ideas which I could look into.

Thank you.

Hi Phil,


Thank you for your feedback.

Will it be possible for you to share your sample application for our review? So we may execute it at our end to confirm your said behaviour.

Regards,