Domanda

Sto cercando di scrivere un servizio di notifica (per scopi non spam completamente legit) in .NET utilizzando SmtpClient. Inizialmente ho appena loop con ogni messaggio e lo ha inviato, tuttavia questo è lento e vorrei migliorare la velocità. Quindi, sono passato ad usare 'SendAsync', ma ora ottengo il seguente errore sulla seconda chiamata:

An asynchronous call is already in progress. 

Ho letto questo a significare che la SM paralizzato System.Net.Mail per evitare mass-mailer. È corretto? Se è così, c'è un modo migliore per fare questo in .NET, e ancora in grado di registrare i risultati di ogni e-mail (che è importante per il nostro cliente). Se no, perché può SendAsync essere chiamato solo una volta?

È stato utile?

Soluzione

In base alla :

  

Dopo aver chiamato SendAsync, è necessario attendere   per la trasmissione e-mail a   completare prima di inviare   un altro messaggio di posta elettronica utilizzando Invia o   SendAsync.

Quindi, per inviare più mail allo stesso tempo è necessario più istanze SmtpClient.

Altri suggerimenti

Si potrebbe essere in grado di utilizzare il seguente:

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

Questo dovrebbe permettere che i messaggi vengano messi in coda e inviati come le discussioni diventano disponibili.

Ovviamente, questo non è un tentativo di fermare mass mailer.

Il motivo è che la classe SmtpClient non è thread-safe. Se si desidera inviare più email contemporaneamente, è necessario generare un paio di thread di lavoro (ci sono alcuni modi per farlo in .NET Framework) e creare istanze separate di SmtpClient in ognuno di loro.

Credo che tu frainteso la classe XXXAsync di metodi. Lo scopo di queste chiamate asincrone è quello di consentire al programma di continuare la corsa, senza la necessità del metodo per terminare l'elaborazione e tornare prima. È quindi possibile procedere con il risultato più tardi da iscriversi a qualcosa di simile evento XXXReceived dell'oggetto.

Per inviare più di una posta elettronica contemporaneamente, si può considerare l'utilizzo di più Threads.

È possibile inviare solo uno alla volta per ogni client SMTP. Se si desidera effettuare più di una chiamata di invio, creare più di un client SMTP.

HTH,

Colby Africa

Come notato da tutti gli altri qui, è possibile inviare una sola e-mail alla volta, ma il modo di inviare un altro una volta che il primo è stato inviato è quello di gestire l'evento .SendCompleted della classe SmtpClient, e poi passare al email seguente e inviare tale.

Se si desidera inviare molte email contemporaneamente, poi come gli altri hanno detto, utilizzare più oggetti SmtpClient.

C'è un motivo per riutilizzare il SmtpClient , che limita il numero di connessioni al server SMTP. Non riesco a un'istanza di una nuova classe SmtpClient classe per ogni discussione i rapporti stanno costruendo o il server SMTP sarà esitano con troppi errori connessioni. Questa è la soluzione mi è venuta quando non riuscivo a trovare una risposta qui.

Ho finito per usare un AutoResetEvent per tenere tutto sincronizzato. In questo modo, posso continuare a chiamare il mio SendAsync in ogni thread, ma attendere che si elaborare la posta elettronica e utilizzare il SendComplete evento per ripristinare in modo che il prossimo possa continuare.

I ha installato il reset automatico evento.

        AutoResetEvent _autoResetEvent = new AutoResetEvent(true);

I ha installato il client SMTP condiviso, quando la mia classe viene creata un'istanza.

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

Poi, quando chiamo l'asincrono di invio, io aspetto l'evento per cancellare, quindi inviare quello successivo.

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

Io uso l'evento SMTPClient SendComplete per ripristinare l'AutoResetEvent così la prossima e-mail invierà.

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--;
        }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top