为什么SmtpClient.SendAsync只能调用一次?

发布于 2024-07-10 22:34:18 字数 346 浏览 6 评论 0原文

我正在尝试使用 SmtpClient 在 .NET 中编写通知服务(出于完全合法的非垃圾邮件目的)。 最初我只是循环遍历每条消息并发送它,但是这很慢,我想提高速度。 因此,我改用“SendAsync”,但现在在第二次调用时出现以下错误:

An asynchronous call is already in progress. 

我读到这意味着 MS 削弱了 System.Net.Mail 以防止群发邮件。 它是否正确? 如果是这样,是否有更好的方法在 .NET 中执行此操作,并且仍然能够记录每封电子邮件的结果(这对我们的客户很重要)。 如果不是,为什么SendAsync只能调用一次?

I'm trying to write a notification service (for completely legit non-spam purposes) in .NET using SmtpClient. Initially I just looped through each message and sent it, however this is slow and I would like to improve the speed. So, I switched to using 'SendAsync', but now get the following error on the second call:

An asynchronous call is already in progress. 

I read this to mean that MS crippled System.Net.Mail to prevent mass-mailers. Is this correct? If so, is there a better way to do this in .NET, and still be able to log the results of each email(which is important to our client). If not, why can SendAsync only be called once?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

故事灯 2024-07-17 22:34:18

根据文档

调用SendAsync后,必须等待
用于将电子邮件传输至
在尝试发送之前完成
使用发送或发送另一封电子邮件
发送异步。

因此,要同时发送多封邮件,您需要多个 SmtpClient 实例。

According to the documentation:

After calling SendAsync, you must wait
for the e-mail transmission to
complete before attempting to send
another e-mail message using Send or
SendAsync.

So to send multiple mails at the same time you need multiple SmtpClient instances.

疯到世界奔溃 2024-07-17 22:34:18

您也许可以使用以下内容:

ThreadPool.QueueUserWorkItem(state => client.Send(msg));

这应该允许您的消息排队并在线程可用时发送。

You might be able to use the following:

ThreadPool.QueueUserWorkItem(state => client.Send(msg));

This should allow your messages to be queued and sent as threads become available.

小猫一只 2024-07-17 22:34:18

显然,这并不是为了阻止群发邮件。

原因是 SmtpClient 类不是线程安全的。 如果要同时发送多封电子邮件,则必须生成一些工作线程(.NET Framework 中有多种方法可以实现此目的)并在每个线程中创建单独的 SmtpClient 实例。

Obviously, this is not an attempt to stop mass mailers.

The reason is that the SmtpClient class is not thread safe. If you want to send multiple emails simultaneously, you have to spawn a few worker threads (there are a few ways to do that in the .NET Framework) and create separate instances of SmtpClient in each of them.

生生漫 2024-07-17 22:34:18

我认为您误解了 XXXAsync 类方法。 这些异步调用的目的是让程序继续运行,而不需要方法先完成处理并返回。 然后,您可以稍后通过订阅对象的 XXXReceived 事件来继续处理结果。

要同时发送多封邮件,您可以考虑使用更多Thread

I think you misunderstand the XXXAsync class of methods. The purpose of these asynchronous calls is to allow the program to continue running, without the need of the method to finish processing and return first. You can then proceed with the result later by subscribe to something like XXXReceived event of the object.

To send more than one mail simultaneously, you may consider using more Threads.

哆兒滾 2024-07-17 22:34:18

每个 SMTP 客户端一次只能发送一个。 如果您希望进行多个发送调用,请创建多个 SMTP 客户端。

HTH,

科尔比非洲

You may only send one at a time per SMTP client. If you wish to make more than one send call, create more than one SMTP client.

HTH,

Colby Africa

别把无礼当个性 2024-07-17 22:34:18

正如这里其他人所注意到的,您一次只能发送一封电子邮件,但是在发送第一封电子邮件后发送另一封电子邮件的方法是处理 SmtpClient 类的 .SendCompleted 事件,然后继续发送下一封电子邮件并发送那个。

如果您想同时发送多封电子邮件,那么正如其他人所说,请使用多个 SmtpClient 对象。

As noticed by everyone else here, you can only send one email at a time, but the way to send another once the first has been sent is to handle the .SendCompleted event of the SmtpClient class, and then move on to the next email and send that.

If you want to send many emails simultaneously, then as the others have said, use multiple SmtpClient objects.

瑕疵 2024-07-17 22:34:18

重用SmtpClient是有原因的,它限制了与 SMTP 服务器的连接数量。 我无法为构建报告的每个线程实例化一个新类 SmtpClient 类,否则 SMTP 服务器将因连接过多错误而犹豫不决。 这是我在这里找不到答案时想到的解决方案。

我最终使用 AutoResetEvent 来保持一切同步。 这样,我可以继续在每个线程中调用 SendAsync,但等待它处理电子邮件并使用 SendComplete 事件来重置它,以便下一个线程可以继续。

我设置了自动重置事件。

        AutoResetEvent _autoResetEvent = new AutoResetEvent(true);

当我的类实例化时,我设置了共享 SMTP 客户端。

        _smtpServer = new SmtpClient(_mailServer);
        _smtpServer.Port = Convert.ToInt32(_mailPort);
        _smtpServer.UseDefaultCredentials = false;
        _smtpServer.Credentials = new System.Net.NetworkCredential(_mailUser, _mailPassword);
        _smtpServer.EnableSsl = true;
        _smtpServer.SendCompleted += SmtpServer_SendCompleted;

然后,当我调用发送异步时,我等待事件清除,然后发送下一个。

        _autoResetEvent.WaitOne();
        _smtpServer.SendAsync(mail, mail);
        mailWaiting++;

我使用 SMTPClient SendComplete 事件重置 AutoResetEvent,以便发送下一封电子邮件。

private static void SmtpServer_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            MailMessage thisMesage = (MailMessage) e.UserState;
            if (e.Error != null)
            {
                if (e.Error.InnerException != null)
                {
                    writeMessage("ERROR: Sending Mail: " + thisMesage.Subject + " Msg: "
                                 + e.Error.Message + e.Error.InnerException.Message);
                }

                else
                {
                    writeMessage("ERROR: Sending Mail: " + thisMesage.Subject + " Msg: " + e.Error.Message);
                }
            }
            else
            {
                writeMessage("Success:" + thisMesage.Subject + " sent.");
            }
        if (_messagesPerConnection > 20)
        {  /*Limit # of messages per connection, 
            After send then reset the SmtpClient before next thread release*/
            _smtpServer = new SmtpClient(_mailServer);
            _smtpServer.SendCompleted += SmtpServer_SendCompleted;
            _smtpServer.Port = Convert.ToInt32(_mailPort);
            _smtpServer.UseDefaultCredentials = false;
            _smtpServer.Credentials = new NetworkCredential(_mailUser, _mailPassword);
            _smtpServer.EnableSsl = true;
            _messagesPerConnection = 0;
        }
            _autoResetEvent.Set();//Here is the event reset
            mailWaiting--;
        }

There is a reason to reuse the SmtpClient, it limits the # of connections to the SMTP server. I cannot instantiate a new class SmtpClient class for each thread the reports are building on or the SMTP server will balk with too many connections error. This is the solution I came up with when I couldn't find an answer here.

I ended up using an AutoResetEvent for keeping everything in sync. That way, I can keep calling my SendAsync in each thread, but wait for it to process the email and use the SendComplete event to reset it so the next one can continue.

I setup the Auto Reset Event.

        AutoResetEvent _autoResetEvent = new AutoResetEvent(true);

I setup the shared SMTP Client when my class is instantiated.

        _smtpServer = new SmtpClient(_mailServer);
        _smtpServer.Port = Convert.ToInt32(_mailPort);
        _smtpServer.UseDefaultCredentials = false;
        _smtpServer.Credentials = new System.Net.NetworkCredential(_mailUser, _mailPassword);
        _smtpServer.EnableSsl = true;
        _smtpServer.SendCompleted += SmtpServer_SendCompleted;

Then when I call the send async, I wait for the event to clear, then send the next one.

        _autoResetEvent.WaitOne();
        _smtpServer.SendAsync(mail, mail);
        mailWaiting++;

I use the SMTPClient SendComplete event to reset the AutoResetEvent so the next email will send.

private static void SmtpServer_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            MailMessage thisMesage = (MailMessage) e.UserState;
            if (e.Error != null)
            {
                if (e.Error.InnerException != null)
                {
                    writeMessage("ERROR: Sending Mail: " + thisMesage.Subject + " Msg: "
                                 + e.Error.Message + e.Error.InnerException.Message);
                }

                else
                {
                    writeMessage("ERROR: Sending Mail: " + thisMesage.Subject + " Msg: " + e.Error.Message);
                }
            }
            else
            {
                writeMessage("Success:" + thisMesage.Subject + " sent.");
            }
        if (_messagesPerConnection > 20)
        {  /*Limit # of messages per connection, 
            After send then reset the SmtpClient before next thread release*/
            _smtpServer = new SmtpClient(_mailServer);
            _smtpServer.SendCompleted += SmtpServer_SendCompleted;
            _smtpServer.Port = Convert.ToInt32(_mailPort);
            _smtpServer.UseDefaultCredentials = false;
            _smtpServer.Credentials = new NetworkCredential(_mailUser, _mailPassword);
            _smtpServer.EnableSsl = true;
            _messagesPerConnection = 0;
        }
            _autoResetEvent.Set();//Here is the event reset
            mailWaiting--;
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文