views:

384

answers:

3

Here is the set-up:

  1. I have a Notifications controller that is called from task scheduler 1x/day
  2. The action method pulls upwards of 300 addresses, loops thru them and uses the SmtpClient class to send an individual e-mail to each recepient.

From what I can tell the process runs fine with no exceptions ... except that not all e-mails are being delivered. Anyone have any ideas on what is going on and how to resolve?

Here is the code:

foreach (var emp in division.Users)
{
    var fromAddress = "myfromaddress";
    var mailServer = "mymailserver";

    var toEmail = emp.EmailAddress;

    var message = new MailMessage(fromAddress, toEmail)
                    {
                        Subject = subject,
                        Body = "<body style='font:normal 13px tahoma,arial,helvetica;'>" + body + "</body>",
                        IsBodyHtml = true
                    };

    var client = new SmtpClient(mailServer);
    client.Send(message);
}

UPDATE:

Adding a pause in between sending e-mails resolves the problem. But why does this work? And is there a better way (e.g. using Async()) that would equally resolve the issue in a better way???

Updated code ...

foreach (var emp in division.Users)
{
    var fromAddress = "myfromaddress";
    var mailServer = "mymailserver";

    var toEmail = emp.EmailAddress;

    var message = new MailMessage(fromAddress, toEmail)
                    {
                        Subject = subject,
                        Body = "<body style='font:normal 13px tahoma,arial,helvetica;'>" + body + "</body>",
                        IsBodyHtml = true
                    };

    var client = new SmtpClient(mailServer);
    client.Send(message);

    Thread.Sleep(3000); // Wait 3s until sending next message
}
A: 

there is a default timeout with the smtp client and default value is 100sec

more info here

Fredou
I don't think it is the timeout as it isn't taking anywhere close to 100s to send out an individual e-mail.
wgpubs
A: 

I would strongly advice on using SmtpClient.SendAsync() as Send() is blocking.

I would check the logs of the SMTP server that you're sending to. Note: sending your own emails are more likely to end in Junk mail than using a trusted provider.

Edit: added sample SendAsync code

smtpClient.SendCompleted += smtpClient_SendCompleted;

static void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    if (e.Error != null)
    {
        Log.ErrorFormat("Async Mail exception {0} :: {1}", 
            e.Error.GetType().Name, e.Error.Message);
    }
}
mythz
How does this work in an MVC environment? In other words, how do I determine success, failure, etc...?
wgpubs
doing async call in asp.net is really tricky
Fredou
@Fredou How so? All that needs to be changed is to call SendAsync and provide an event handler for the SendCompleted event...
Nate Bross
@Fredou edited answer to include example for checking errors in async call
mythz
I'm still not sure how this works in an ASP.NET MVC environment where I have a controller (NotificationsController) with an action method (SendNotifications) that does this work. As far as I'm aware, after the SendNotifications method completes, the instance of "NotificaitonsController" is garbage collected making it unavailable to receive the messages from Async, no?
wgpubs
I believe that since the the SmtpClient.SendCompleted will still be holding a reference to the event handler (defined in the NotificationsController) it should stick around until all have completed, with or without an error.
Nate Bross
I'll have to test. I do notice that if I pause in between sending mail (Thread.Sleep(3000) ... 3s) ... ALL of the emails are sent. So I'm wondering if it has something to do with pounding the mailserver one right after another????
wgpubs
http://msdn.microsoft.com/en-us/magazine/cc163725.aspx and http://download.microsoft.com/download/4/1/9/4194800d-ba53-423b-a379-f668cb08502c/cs_sc-Asynchronous%20Email_cs.zip
Fredou
A: 

If you are not having any exceptions I'd check SPAM folders and email addresses. I'd also try sending an email manually from your outlook to one of the addresses that didn't recieve a message.

On a side note, unless you are using different mail servers, I think you can change this code to

var client = new SmtpClient(mailServer); 
var mailServer = "mymailserver";

foreach (var emp in division.Users) 
{ 
    var fromAddress = "myfromaddress"; 


    var toEmail = emp.EmailAddress; 

    var message = new MailMessage(fromAddress, toEmail) 
                    { 
                        Subject = subject, 
                        Body = "<body style='font:normal 13px tahoma,arial,helvetica;'>" + body + "</body>", 
                        IsBodyHtml = true 
                    }; 


    client.Send(message); 
} 

You might also try SendAsync method of the SmtpClient class, like this:

// setup the callback method when the send finishes
client.SendCompleted += SendComplete; //new SendCompletedEventHandler(smtpSender_SendCompleted);

// send the email
client.SendAsync(message, null);



private void SendComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    // do stuff on complete
}
Nate Bross
Nope ... junk, spam folders don't have the message either
wgpubs
I have a similar application using the SendAsync method and it sends 100s of emails without issues...
Nate Bross
@Nate: In an ASP.NET MVC app?
wgpubs
No, it is a windows service... but that should not make a difference since the code is mostly the same. Try using the Async method and then investigate the AsyncCompletedEventArgs object to see if any errors are happening.
Nate Bross