Pergunta

Eu estou tentando escrever um serviço de notificação (para fins não-spam completamente legítimas) em .NET usando SmtpClient. Inicialmente eu apenas loop através de cada mensagem e enviá-lo, porém este é lento e eu gostaria de melhorar a velocidade. Então, eu passou a usar 'SendAsync', mas agora obter o seguinte erro na segunda chamada:

An asynchronous call is already in progress. 

Eu li isto para dizer que MS aleijado System.Net.Mail para evitar massa-utentes. Isso é correto? Se assim for, há uma maneira melhor de fazer isso em .NET, e ainda ser capaz de registrar os resultados de cada e-mail (que é importante para o nosso cliente). Se não, por que pode SendAsync ser chamado apenas uma vez?

Foi útil?

Solução

De acordo com a documentação :

Depois de chamar SendAsync, você deve esperar para a transmissão de e-mail para completar antes de tentar enviar outra mensagem de e-mail usando a opção Enviar ou SendAsync.

Assim, para enviar vários e-mails ao mesmo tempo que você precisa várias instâncias SmtpClient.

Outras dicas

Você pode ser capaz de usar o seguinte:

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

Isso deve permitir que suas mensagens sejam enfileiradas e enviadas como threads se tornam disponíveis.

Obviamente, isso não é uma tentativa de utentes em massa de parada.

A razão é que a classe SmtpClient não é thread-safe. Se você quiser enviar vários e-mails ao mesmo tempo, você tem que gerar alguns segmentos de trabalho (há algumas maneiras de fazer isso no .NET Framework) e criar instâncias separadas de SmtpClient em cada um deles.

Eu acho que você não entendeu a classe XXXAsync de métodos. O objectivo destas chamadas assíncronas é permitir que o programa continue a funcionar, sem a necessidade do método para terminar o processamento e retornar primeiro. Você pode então prosseguir com o resultado mais tarde por se inscrever para algo como evento XXXReceived do objeto.

Para enviar mais de um e-mail ao mesmo tempo, você pode considerar o uso de mais Threads.

Você só pode enviar um de cada vez por cliente SMTP. Se você quiser fazer mais do que uma chamada de envio, criar mais de um cliente SMTP.

HTH,

Colby África

Como notado por todos os outros aqui, você só pode enviar um e-mail de cada vez, mas a maneira de enviar outra vez o primeiro enviado tem sido é manipular o evento .SendCompleted da classe SmtpClient, e depois passar para a próximo e-mail e enviar isso.

Se você quiser enviar muitos e-mails ao mesmo tempo, então, como os outros disseram, usar vários objetos SmtpClient.

Há uma razão para reutilizar o SmtpClient , que limita o # de conexões com o servidor SMTP. Eu não pode instanciar uma nova classe SmtpClient classe para cada thread os relatórios estão construindo em ou o servidor SMTP vai reclamar com muitos erros conexões. Esta é a solução que eu vim acima com quando eu não poderia encontrar uma resposta aqui.

Acabei usando um AutoResetEvent para manter tudo em sincronia. Dessa forma, eu posso manter chamando meu SendAsync em cada segmento, mas esperar por ele para processar o e-mail e usar o SendComplete evento para redefini-la de modo que o próximo pode continuar.

I configuração Reset Evento Auto.

        AutoResetEvent _autoResetEvent = new AutoResetEvent(true);

Eu configurei o cliente SMTP compartilhado quando minha classe é instanciado.

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

Então, quando eu chamar o assíncrono send, eu aguardar o evento para limpar, em seguida, enviar o próximo.

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

Eu uso o evento SMTPClient SendComplete para repor o AutoResetEvent então o próximo e-mail será enviado.

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--;
        }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top