Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么只能调用SmtpClient.SendAsync一次?_C#_Smtpclient_System.net.mail - Fatal编程技术网

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

C# 为什么只能调用SmtpClient.SendAsync一次?,c#,smtpclient,system.net.mail,C#,Smtpclient,System.net.mail,我正在尝试使用SmtpClient在.NET中编写一个通知服务(用于完全合法的非垃圾邮件目的)。起初,我只是循环发送每条消息,但是速度很慢,我想提高速度。因此,我切换到使用“SendAsync”,但在第二次调用中出现以下错误: An asynchronous call is already in progress. 我读这篇文章的意思是,微软瘫痪了System.Net.Mail,以防止群发邮件。这是正确的吗?如果是这样,有没有更好的方法在.NET中这样做,并且仍然能够记录每封电子邮件的结果(

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

An asynchronous call is already in progress. 

我读这篇文章的意思是,微软瘫痪了System.Net.Mail,以防止群发邮件。这是正确的吗?如果是这样,有没有更好的方法在.NET中这样做,并且仍然能够记录每封电子邮件的结果(这对我们的客户很重要)。如果没有,为什么SendAsync只能调用一次?

显然,这不是阻止群发邮件的尝试

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

根据:

调用SendAsync后,必须等待 用于将电子邮件传输到 在尝试发送之前完成 另一封使用“发送”或“发送”的电子邮件 SendAsync


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

每个SMTP客户端一次只能发送一个。如果要进行多个发送呼叫,请创建多个SMTP客户端

嗯,


科尔比非洲

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


同时发送多个邮件,可以考虑使用更多的<代码>线程 S.

,如这里的每个人都注意到,每次只能发送一封电子邮件,但是发送第一次发送的另一种方式是处理SMTPclipse类的.sEndodError事件,然后转到下一封电子邮件并发送。


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

您可以使用以下内容:

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

这将允许您的邮件在线程可用时排队并发送。

重新使用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;
然后,当我调用send async时,我等待事件清除,然后发送下一个事件

        _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--;
        }

多线程调用SendAsync正是导致这种情况的原因exception@statichippoOP最初没有使用异步版本的send mail。我建议在非异步调用中使用多个线程。如果在多个线程上调用Send(非异步),则会出现异常。SmtpClient类一次只能发送一条消息,而不管有多少线程在发送它。这是一个协议问题,不是C#问题真的。。。在发送另一条消息之前,您必须等待一条消息被发送——无论您使用的是SendAsync还是Send。除非你想创建多个SmtpClientsDoesn,否则没有人已经实现了这样一种机制,一次发送多封电子邮件吗?在smtp客户端类之上?听起来像是很多人遇到的问题。。。有点奇怪,从来没有人为它创建过框架。@ItayLevin我认为没有必要尝试重用SmtpClient实例。为什么不像Darin熟练地解释的那样,只为每次电子邮件发送尝试指定每个实例。这是一个关于该主题的讨论。问题是,如果您有多个实例,您可能会因为连接太多而被SMTP服务器阻止。共享实例允许您通过一个连接发送多条消息,而无需运行该连接。我有我的解决方案,如果您愿意,也可以解决。当从同一个
SmtpClient
实例发送时,此实现仍然可能会产生
System.InvalidOperationException
。如果您使用的是.NET 4.0或更高版本,您应该看看
SemaphoreSlim
ManualResetEventSlim
,它们速度更快,因为它们不依赖Win32内核对象()。