6

I am trying to send a lot of emails to using SmtpClient.SendMailAsync method. Here is my test method that I call from the simple console application.

    static void Main(string[] args)
    {

        SendMailsOnebyOneAsync().GetAwaiter().GetResult();

    }


    public static async Task SendMailsOnebyOneAsync()
    {
        for (int i = 0; i < 1000; i++)
        {
            try
            {
                using (SmtpClient sMail = new SmtpClient("XXX"))
                {
                    sMail.DeliveryMethod = SmtpDeliveryMethod.Network;
                    sMail.UseDefaultCredentials = false;
                    sMail.Credentials = null;

                    var fromMailAddress = new MailAddress("XXX");
                    var toMailAddress = new MailAddress("XXX");

                    MailMessage message = new MailMessage(fromMailAddress, toMailAddress)
                    {
                        Subject = "test"
                    };

                    await sMail.SendMailAsync(message);

                    Console.WriteLine("Sent {0}", i);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }

Sometimes the method is hanging - it awaits to SendMailAsync which seems stuck and doesn't return.

I see one related question SmtpClient SendMailAsync sometimes never returns . But there is no fix suggested that works for me.

When I tried to use the synchronous method SmtpClient.Send everything is OK and application never hangs.

Does anybody have any idea what is wrong?

pfx
  • 20,323
  • 43
  • 37
  • 57
Inako
  • 259
  • 5
  • 13
  • Do you have access to the SMTP server? Reviewing the logs may reveal the issue. – tj-cappelletti Feb 07 '19 at 20:48
  • Know that you cannot send async 2 billions emails. I'm exaggerating but you are limited physically to a certain amount. In your case the email is very small but if it's just a sample code and the real one you have attachment an such you email by be 1-2mb and this completely kills your network card sending 1000 emails in the same second especially when at best you can send 60-70 per seconds on a gigabit network. – Franck Feb 07 '19 at 20:50
  • 1
    id check with whatever smtp service you're using on any rate limits they have-most popular services will have them. To over come it, you could use a queue (lots of diff implementations for queues out there- database, rabbitMQ, EASendMail, MSMQ, etc) in this sort of situation where you have lots and lots of email that go out. If it's your own smtp server then as @virusstorm said, take a look at the logs – GregH Feb 07 '19 at 21:02
  • I will try to look into logs if will get get access. – Inako Feb 08 '19 at 14:00
  • Question - in case of "Killing network Card" that Frank mentioned should I get any exception or it is just hanging ? – Inako Feb 08 '19 at 14:02
  • Also I don't understand why it is working OK with the non async method if the problem in "Killing Network Card" – Inako Feb 08 '19 at 14:05
  • @Inako Typically no you will never get any errors async as the SMTP server is most likely the one that throttle everything. You can check for event viewer logs to see smtp fails if you are tracking them or if they fail on the smtp server you can sometime read logs that tell you if an email failed. As GregH suggested queueing is the best option. Personally i have dabbled with MSMQ for this kind of work and it works very well. Non async is automatically limited by your OS and cannot send anymore if saturated so it has to wait. Watch out for being marked as zombie emailer by ISP. – Franck Feb 12 '19 at 16:06

3 Answers3

2

Use one client to send the repeated mails. Continuously creating and disposing that many clients can have port issues.

public static async Task SendMailsOnebyOneAsync() {
    using (var sMail = new SmtpClient("XXX")) {
        sMail.DeliveryMethod = SmtpDeliveryMethod.Network;
        sMail.UseDefaultCredentials = false;
        sMail.Credentials = null;

        for (int i = 0; i < 1000; i++) {
            try {
                var fromMailAddress = new MailAddress("XXX");
                var toMailAddress = new MailAddress("XXX");

                var message = new MailMessage(fromMailAddress, toMailAddress) {
                    Subject = "test"
                };

                await sMail.SendMailAsync(message);

                Console.WriteLine("Sent {0}", i);
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            }
        }
    }
}

Secondly, though probably just as this is an example, its is unreasonable to try and send that many emails in one go.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
2

One on my colleague pointed me to the fact that SmtpClient is actually obsolete and Microsoft recommends not to use it.

See the following link.

     ************ Update ***********

I have tried to use MailKit as recommended in the link. The same scenario is working perfectly with MailKit for both non async and async sending.

   **********************************
Inako
  • 259
  • 5
  • 13
0
  • For sending large number of emails with SmtpClient I remember that it was recommended to reuse the same connection.
  • I would change the way how you handle async for this. Try the ThreadPool.

As a side note, SmtpClient doesn't support modern protocols. It's still ok to use for the occasional email for internal uses and tests.
You can try MailKit

tatigo
  • 2,174
  • 1
  • 26
  • 32