.NET melhor método para enviar e-mail (System.Net.Mail tem problemas)
-
06-09-2019 - |
Pergunta
Este parece ser bastante simples. Eu preciso enviar e-mail a partir de algumas aplicações ASP.NET. Eu preciso fazer isso de forma consistente, sem erros estranhos e sem a utilização da CPU atravessando o telhado. Eu não estou falando de e-mail em massa, e-mails apenas ocasionais.
System.Net.Mail aparece para ser horrivelmente quebrado. faz o SmtpClient não emitir o comando Quit (pode ser porque o Microsoft (R) não está interessado em seguintes especificações), portanto, uma conexão é deixada em aberto. Portanto, se alguém tenta enviar e-mail antes que conexão finalmente fecha, você pode obter erros do servidor SMTP sobre muitas conexões abrir. Este é um bug que a Microsoft (R) é completamente desinteressado na fixação. Veja aqui:
http://connect.microsoft.com/VisualStudio/feedback/ ViewFeedback.aspx? FeedbackID = 146711
Além disso, se você olhar em volta alguns sugerem usar este código para resolver este problema:
smtpClient.ServicePoint.MaxIdleTime = 1;
smtpClient.ServicePoint.ConnectionLimit = 1;
Ok, sim, que significa "resolver" o problema de conexões sendo deixada em aberto. No entanto, isso de forma consistente, experimentá-lo em um servidor, se quiser, faz com que a CPU na qual o processo (neste caso w3wp.exe) está sendo executado para saltar e permanecem em 100% até o seu pool de aplicativos é reciclado. Por alguma razão, o fio que corre MSCORWKS.DLL! CreateApplicationContext é o culpado.
Isto tem o efeito colateral muito agradável que, se você estiver executando em um host que franze a testa sobre o uso da CPU sustentada 100%, você vai ter o seu pool de aplicativos desativado. Então isso não é tão trivial como alguns sugerem.
Então, minha pergunta é o que fazer? O que eu preciso fazer é tão simples; no entanto obter essas "muitas conexões abertas" erros não é aceitável e nem é o uso de CPU de 100%. Eu não quero comprar um componente de terceiros, não porque eu sou barato, mas eu comprar suficientes componentes e assinatura do MSDN que parece loucura ter que desembolsar US $ 100- $ 300 para a funcionalidade SMTP simples.
Eu li que a configuração da MaxIdleTime maior pode ajudar, mas eu sou cético em relação a isso. Eu não quero arriscar meu pool de aplicativo que está sendo desativada só porque a Microsoft não quer seguir a especificação do SMTP.
Editar: Eu olhei para quiksoft.com componentes, no entanto, ele não suporta a autenticação SMTP e custa US $ 500. Tem que ser uma solução para este problema.
Solução
I enfrentou o mesmo problema de utilização da CPU com as configurações descritas. Acabei de abrir um ticket com a Microsoft para determinar a causa do problema. O problema a utilização da CPU está na classe ServicePoint. Internamente na classe ServicePoint, há um temporizador que sai a cada (MaxIdleTime / 2) milissegundos. Ver o problema? Alterando o valor MaxIdleTime a 2, a utilização da CPU irá cair para níveis normais.
Outras dicas
Em .NET 4.0, SmtpClient agora é descartável. O SMTP QUIT comando é emitido quando da alienação tal como quando usado em um bloco usando.
Eu sempre usei componentes do Quiksoft EasyMail .NET sem problemas em tudo.
Produtos home page: http://www.quiksoft.com/emdotnet/
Eles também têm uma versão gratuita do componente se você só precisa enviar e-mails:
Temos usado hMailServer com grande sucesso. A configuração pode demorar um pouco para se acostumar, mas ele tem sido um grande - e gratuita -. Correio produto de servidor
Se você desejar construir sua própria (que eu fiz anos atrás, quando eu estava tendo um urso de um tempo com CDONTS), você pode começar com o código abaixo e personalização para o conteúdo do seu coração. Ele usa o TcpClient para criar uma conexão TCP diretamente para o servidor de correio. Não que eu recomendo este quando há tantas soluções estabelecidas e depurado, mas eu achei isso muito útil para depuração e determinar onde o problema era com os componentes pré-fabricada de correio MS.
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:from@address.com\n";
strMail += "RCPT TO:" + recipient + "\n";
strMail += "DATA\n";
strMail += "Subject: mySubject\n";
strMail += "To:" + recipient + "\n";
strMail += "From: \"From Real Name\" <from@address.com>\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
}
Enquanto eu não tive quaisquer problemas específicos com System.Net.Mail
até agora, você sempre pode usar o velho System.Web.Mail
API que é um wrapper para CDOSYS.
Eu usei Quicksoft no passado e não tenho queixas. Outra coisa que você pode tentar é mudar a configuração SMTP para usar uma pasta de retirada em vez de enviar usando a rede que deve começar em torno do "ele não envia SAIR" a questão.
I enviar a maioria de meu e-mail usando um Sproc. Eu até posso anexar um arquivo.
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