Send mails asynchronously in wcf

Hello,

I am doing a wcf C#.net project in which i need to send multiple emails asynchronously with one pdf attachment. I use smtp.sendAsync() to do it. Please guide me on this and clarify my doubts.

The logic i have used is, store all the receiver’s email ids in a list. Then, in a foreach loop, inside each loop call my function say, sendMailsaAsynch(objList, filename). This function is responsible for opening the pdf file using the filename specified, and attach it to a new object of MailAddress and call smtp.sendAsync().


function sendMailsAsynch(objList, filename)
{
//open the file
fs = new FileStream(...)           //LINE 1
mm = new MailMessage();
Attachment a = ....
.. smtp = new
try
{
 smtp.SendCompleted += new SendCompletedEventHandler(smtp_OnCompleted);
 smtp.sendAsynch();
}
catch{ throw;}
finally { }

}

I want to delete the file in the finally. but i cannot access the file. Because, it says file is used by w3wp.exe. If i use mm.Dispose() in finally, none of the emails is sent. You may ask why i open the same file in every each loop in the LINE 1. But IF i do it in the calling function as shown below in the commented line, none of the emails are sent. I get Failure sending mail. some error like: Cannot access the mailaddress object. (Please explain where i can delete the file and how to delete it. I created the file using fs = new FileStream(filename, FileMode.Open, FileAccess.Read))

The following is how i call the function in foreach loop.


funcion sendMails(List list)
{
   //fs = new FileStream(....)
   foreach(List l in list)
   {
      sendMailsAsynch(list, filenme);
   }
}

One more important thing is: If i keep breakpoint and check in the smtp_OnCompleted delegate function, sometimes the breakpoint is hit after all the try-catch-finally is completed. ie. after all the loops are finished. But sometimes i get the breakpoint hit on this delegate function after the end of each try-cath ie. at the end for each loop. Can anyone explain how threading is handled here.

I do not want to use MessageQueing. I think it is not much of a complex issue. Hope someone will surely solve this. Thanks in advance.

Asynch and multi-threading are difficult. Welcome to the big leagues. Looking at what you are doing I don’t think your asynch approach is winning you anything except nasty multi-threaded debugging. Unless you are going to use multiple SMTP servers so you aren’t waiting on the server to send things.

A much easier approach here would be to setup your mail to use the pickup directory. You could probably then just run it in single-threaded, synchronous mode and do fine as that is much quicker then waiting on SMTP. A vastly superior option would be to use a service bus to handle this – you tell the service bus basic instructions, it will turn around and pickup and send the mails in the background. You could model this as a batch which would send another message when done to delete the file, though I would probably just model individual messages and include the file with each to avoid the common point of contention.

If you really want to do this multi-threaded sending you should check out Tasks rather than using the old AsyncModel. The problem in your code with deleting the file and mail objects crashing is that you are not waiting for the async tasks to be completed. Doing this by hand is quite a bit of boilerplate code – you’ll need to fire these off, handle the async results and signal the main thread that everyone is completed. And that doesn’t even get into exception handling. Tasks make this much easier as they handle that plumbing for you so your code would look something like:


var tasks = new task[list.Count];
for (int i=0; i < list.Count; i++){
    tasks[i] = new Task(() => {
       // do mail sending stuff here
    });
    // kick off task.
    tasks[i].Start();
}
// wait for all the tasks to complete
Task.WaitAll(tasks);
// cleanup file, etc.