2009-05-30 12 views
18

Questo sembra essere abbastanza semplice. Devo inviare e-mail da alcune applicazioni ASP.NET. Devo farlo in modo coerente senza strani errori e senza l'utilizzo della CPU che passa attraverso il tetto. Non sto parlando di e-mail di massa, solo e-mail occasionali..NET Metodo migliore per inviare e-mail (System.Net.Mail ha problemi)

System.Net.Mail appare per essere rotto in modo orribile. SmtpClient non emette il comando Quit (potrebbe essere perché Microsoft (R) non è interessato a seguire le specifiche), quindi una connessione è lasciata aperta. Pertanto, se qualcuno tenta di inviare un'email prima che la connessione alla fine si chiuda, è possibile ottenere errori dal server SMTP su troppe connessioni aperte. Questo è un bug che Microsoft (R) non è completamente interessato a correggere. Vedi qui:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=146711

Inoltre, se si guarda intorno un po 'consigliato l'utilizzo di questo codice per risolvere questo problema:

smtpClient.ServicePoint.MaxIdleTime = 1; 
smtpClient.ServicePoint.ConnectionLimit = 1; 

Ok, sì che significa "risolvere" il problema dei collegamenti essere lasciato Aperto. Tuttavia, in modo coerente, provalo su un server, se lo desideri, provoca la CPU su cui il processo (in questo caso w3wp.exe) è in esecuzione per saltare e rimanere al 100% fino a quando il pool di applicazioni non viene riciclato. Per qualsiasi motivo, il thread che esegue mscorwks.dll! CreateApplicationContext è il colpevole.

Questo ha l'effetto collaterale molto piacevole che se si sta eseguendo su un host Web che si acciglia su un utilizzo prolungato della CPU al 100%, si otterrà il pool di applicazioni disabilitato. Quindi questo non è così banale come alcuni suggeriscono.

Quindi la mia domanda è cosa fare? Quello che devo fare è così semplice; tuttavia ottenere quegli errori "troppe connessioni aperte" non è accettabile e nemmeno l'utilizzo della CPU al 100%. Non voglio acquistare un componente di terze parti, non perché sono a buon mercato, ma compro abbastanza componenti e abbonamento MSDN che sembra folle dover sborsare $ 100- $ 300 per la semplice funzionalità SMTP.

Ho letto che l'impostazione di MaxIdleTime superiore può essere d'aiuto ma sono scettico su questo. Non voglio mettere a rischio il blocco del pool di app solo perché Microsoft non desidera seguire le specifiche SMTP.

Modifica: Ho esaminato i componenti di quiksoft.com, tuttavia non supporta l'autenticazione SMTP e costa $ 500. Deve esserci una soluzione a questo problema.

+0

In base al collegamento fornito, il bug è stato corretto. È possibile che manchi un service pack? – overslacked

+0

Ho visto dove si dice "risolto". Tuttavia non ho visto altre note. Ho aggiornato il server all'ultimo SP e tutto il resto. Quando l'ho visto prima di solito sembra che MS significhi che non lo risolveranno. Hanno anche il "workaround" che ho citato elencato lì. Potrebbe essere molto più chiaro. – JustAProgrammer

risposta

22

Ho affrontato lo stesso problema di utilizzo della CPU con le impostazioni descritte. Ho finito per aprire un ticket con Microsoft per determinare la causa del problema. Il problema di utilizzo della CPU si trova nella classe ServicePoint. Internamente nella classe ServicePoint, esiste un timer che esegue ogni millisecondo (MaxIdleTime/2). Vedi il problema? Modificando il valore MaxIdleTime su 2, l'utilizzo della CPU scenderà ai livelli normali.

+0

Non riesco a "vedere il problema", tuttavia questa correzione funziona. È interessante notare che il valore predefinito di MaxIdleTime è 100000. Quando lo abbiamo impostato su 1, abbiamo aumentato la CPU al 100%. L'impostazione di MaxIdleTime su 2 ha abbassato la CPU a livelli normali, proprio come hai riportato. –

+11

@Scott Ferguson: Il problema è che il timer verrà eseguito a (1/2) millisecondi, che nella divisione di interi valuterà a ... ogni * 0 * millisecondi. Whoopsie. –

1

Mentre non ho avuto alcun problema specifico con System.Net.Mail finora, è sempre possibile utilizzare l'API System.Web.Mail precedente che è un wrapper per CDOSYS.

+0

Per non avere problemi con System.Net.Mail, hai provato a inviare un'email da una delle tue pagine e subito dopo averne inviato un altro dalla pagina? Il tuo server potrebbe consentire più di una connessione. Scommetto che se lanci TCPView, la tua connessione rimane aperta per molto tempo. Inoltre, System.Web.Mail non si basa su quel servizio SMTP locale? Devo inviare e-mail attraverso un host remoto che ha configurato correttamente MX ecc. Per evitare di essere contrassegnato come spam. – JustAProgrammer

+0

Non ho negato che abbia problemi. Ho appena detto che non l'ho incontrato. Non l'ho usato molto (solo semplici moduli "contattaci"). System.Web.Mail non si basa sul server SMTP locale e supporta l'utilizzo di server SMTP remoti. L'ho usato ampiamente. Non è molto elegante ma ha funzionato molto bene. –

+0

Oh, non ero polemico, solo curioso. :) – JustAProgrammer

2

Ho sempre utilizzato i componenti EasyMail .NET di Quiksoft senza alcun problema.

casa

prodotto pagina: http://www.quiksoft.com/emdotnet/

Hanno anche una versione gratuita del componente, se avete solo bisogno di inviare e-mail:

http://www.quiksoft.com/freesmtp/

+0

Sono d'accordo. Siamo passati a Quiksoft dopo numerosi problemi con System.Net.Mail e non ci siamo mai voltati indietro. – HVS

+0

Questo è interessante, vedrò questo. Se qualcun altro ha altri suggerimenti, lo apprezzerei anche io! – JustAProgrammer

+0

La versione gratuita non supporta l'autenticazione SMTP con nome utente e password. Costa $ 500 per questo. – JustAProgrammer

1

Ho usato Quicksoft in passato e non ho lamentele. Un'altra cosa che puoi provare è cambiare la configurazione SMTP per utilizzare una cartella di prelievo invece di inviare usando la rete che dovrebbe aggirare il problema "non invia QUIT".

-1

Invio la maggior parte della mia posta utilizzando un Sproc. Posso persino allegare un file.

 

CREATE PROCEDURE [dbo].[sendMail_With_CDOMessage] 
    @to VARCHAR(64), 
    @CC VARCHAR(1024)='', 
    @BCC VARCHAR(1024)='', 
    @subject VARCHAR(500)='', 
    @body VARCHAR(8000)='' , 
    @from VARCHAR(64), 
    @filename VARCHAR(255)='', 
    @priority INT = 0 
AS 
BEGIN 
    SET NOCOUNT ON 

    DECLARE 
     @handle INT, 
     @return INT, 
     @s VARCHAR(64), 
     @sc VARCHAR(1024), 
     @up CHAR(27), 
     @server VARCHAR(255) 

    SET @s = '"http://schemas.microsoft.com/cdo/configuration/' 

    SELECT 
     @s = 'Configuration.Fields(' + @s, 
     @up = 'Configuration.Fields.Update', 
     @server = 'smtp.yourdomain.com' 



    EXEC @return = sp_OACreate 'CDO.Message', @handle OUT 
    SET @sc = @s + 'sendusing").Value' 
    EXEC @return = sp_OASetProperty @handle, @sc, '2' 
    SET @sc = @s + 'smtpserver").Value' 
    EXEC @return = sp_OASetProperty @handle, @sc, @server 
    EXEC @return = sp_OAMethod @handle, @up, NULL 
    EXEC @return = sp_OASetProperty @handle, 'To', @to 
    EXEC @return = sp_OASetProperty @handle, 'CC', @CC 
    EXEC @return = sp_OASetProperty @handle, 'BCC', @BCC 
    EXEC @return = sp_OASetProperty @handle, 'From', @from 
    EXEC @return = sp_OASetProperty @handle, 'Subject', @subject 
    EXEC @return = sp_OASetProperty @handle, 'HTMLBody', @body  
    EXEC @return = sp_OASetProperty @handle, 'Priority', 'cdoHigh' 

    IF @filename IS NOT NULL 
     EXEC @return = sp_OAMethod @handle, 'AddAttachment', NULL, @filename 

    EXEC @return = sp_OAMethod @handle, 'Send', NULL 
    IF @return 0 
    BEGIN 
     PRINT 'Mail failed.' 
     IF @from IS NULL 
      PRINT 'From address undefined.' 
     ELSE 
      PRINT 'Check that server is valid.' 
    END 
    ELSE 
     PRINT 'Mail sent.' 

    EXEC @return = sp_OADestroy @handle 
END 

2

Abbiamo usato hMailserver con grande successo. La configurazione può impiegare un po 'di tempo per abituarsi, ma è stato un ottimo prodotto server free-mail.

Se si desidera eseguire il rollover (cosa che ho fatto anni fa quando stavo passando un po 'di tempo con CDONTS), è possibile iniziare con il codice qui sotto e personalizzare a vostro piacimento. Usa il TcpClient per creare una connessione TCP direttamente al mailserver. Non che lo consiglierei quando ci sono così tante soluzioni consolidate e debug, ma ho trovato questo molto utile per il debug e determinare dove si trovava il problema con i componenti di posta elettronica prefabbricati.

private void Send_Email() 
    { 
     #region Email Sending Function 
     string strMail = ""; 

     try 
     { 
      // See RFC821 http://www.faqs.org/rfcs/rfc821.html for more specs 
      // TcpClient is an abstraction of a TCP Socket connection 
      TcpClient myTCP = new TcpClient(); 

      // Connect to the mail server's port 25 
      myTCP.Connect(mailserver, 25); 

      // Open a network stream which sends data to/from the TcpClient's socket 
      System.Net.Sockets.NetworkStream ns = myTCP.GetStream(); 

      // The data to send to the mail server, basically a raw SMTP mail message 
      strMail = "HELO\n"; 
      strMail += "MAIL FROM:[email protected]\n"; 
      strMail += "RCPT TO:" + recipient + "\n"; 
      strMail += "DATA\n"; 
      strMail += "Subject: mySubject\n"; 
      strMail += "To:" + recipient + "\n"; 
      strMail += "From: \"From Real Name\" <[email protected]>\n"; 
      strMail += "\n"; 
      strMail += " ---------------------------------------\n"; 
      strMail += "Name:  " + txtName.Text + "\n"; 
      strMail += "Address1: " + txtAddress1.Text + "\n"; 
      strMail += "Address2: " + txtAddress2.Text + "\n"; 
      strMail += "City:  " + txtCity.Text + "\n"; 
      strMail += "State: " + txtState.Text + "\n"; 
      strMail += "Zip:  " + txtZip.Text + "\n"; 
      strMail += "Email: " + txtEmail.Text + "\n"; 
      strMail += "Dealer: " + txtDealer.Text + "\n"; 
      strMail += " ---------------------------------------\n"; 
      strMail += "THIS IS AN AUTOMATED EMAIL SYSTEM. DO NOT REPLY TO THIS ADDRESS.\n"; 
      strMail += "\n.\n"; 

      // Defines encoding of string into Bytes (network stream needs 
      // an array of bytes to send -- can't send strings) 
      ASCIIEncoding AE = new ASCIIEncoding(); 
      byte[] ByteArray = AE.GetBytes(strMail); 

      // send the byte-encoded string to the networkstream -> mail server:25 
      ns.Write(ByteArray, 0, ByteArray.Length); 

      //ns.Read(ByteArray, 0, ByteArray.Length); 
      //lblStatus.Text = ByteArray.ToString(); 

      // close the network stream 
      ns.Close(); 

      // close the TCP connection 
      myTCP.Close(); 
     } 
     catch(Exception ex) 
     { 
      throw new Exception("Couldn't send email: <p>" + ex.Message); 
     } 

     #endregion 

    } 
27

In .NET 4.0, SmtpClient è ora disponibile. Il comando SMTP QUIT viene emesso al momento dello smaltimento, ad esempio quando viene utilizzato in un blocco using.

+1

Questa è la risposta corretta, e l'ho testata io stesso. Si prega di fare +1 su questo commento. – LamonteCristo

+0

Questa è la risposta corretta, puoi semplicemente usare SmtpClient in un blocco usando. – James

+0

Ho provato questo, ma non sembra funzionare come pubblicizzato. Sto ancora ricevendo l'errore "# 4.x.2 Troppi messaggi per questa sessione". Qualcun altro ha lo stesso problema? – Farinha

Problemi correlati