sexta-feira, 4 de setembro de 2009

O dilema do envio de e-mail


Hoje em dia um sistema enviar um e-mail automático é não só comum como uma necessidade. Sistemas enviam e-mails automáticos para usuarios que se cadastram num sistema, enviam login e senha para quem esqueceu, enviam as ofertas da semana e uma infinidade de eventos que acontecem em sistemas online.
Mas não são apenas os sistemas web como e-commerce ou sites de rede social, mas ERP's, CRM, SCM e HRM também enviam e-mails. Pipelines de produção avisam gerentes quando uma variável atingiu um valor crítico ou exige atenção. Por exemplo, quando um determinado produto ou insumo no estoque atinge um determinado nivel, o responsável recebe um e-mail, e , as vezes, o fornecedor também recebe um e-mail com a proposta de compra.
Programas de monitoria de rede, de segurança etc enviam e-amils.
Enfim, as aplicações precisam enviar e-mails para os mais diversos fins. Cada linguagem tem a sua maneira e a sua peculiaridade. Mas o que é necessário para enviar um e-mail?
Pasmem, embora o spam seja uma prática muito feia, quem faz afirma que surte efeitos. Eu mesmo já conheci e comprei várias coisas legais através de spam. Mas foi pouca coisa. O resto eu configurei pra ir pro lixo mesmo. Aliás, o melhor anti-spam que eu conheço é o do gmail. Parabéns para o pessoal da Google.
O mínimo que você precisará é de um servidor de SMTP anônimo, no qual você não precise se autenticar para mandar um e-mail. Esses servidores aceitam que você envie e-mails apenas do host onde está o próprio servidor, ou de algum outro host do mesmo domínio. O IIS já vem com um servidor de smtp. A configuração do servidor de SMTP, bem como as configurações de relay fogem ao escopo desse artigo.
Vamos abordar aqui como mandar um e-mail através de um SMTP anônimo usando o .Net framework 1.1. Depois falaremos sobre como mandar e-mails através de servidores de SMTP autenticado e por último falaremos desses dois assuntos no .Net framework 2.0 ou superior.
Primeiro de tudo, seja em C# ou seja em VB.Net você vai precisar colocar isso no seu using:
using System.Web.Mail;
Depois digite o código da Listagem 1, abaixo, no evento que for disparar um e-mail, por exemplo o evento onclick de um botão, na página de fale conosco.
Listagem 1:

MailMessage message = new MailMessage();
try
{
 //crio o objeto MailMessage, que contem o conjunto de parametros de uma mensagem de e-mail

 //aqui eu configuro os parâmetros da mensagem em si
 message.From = "[[nome]]@[[domínio]]"; //e-mail do remetente, deve vir do web.config (mas pode ser  fixo se for uma unica pagina de fale conosco e você não tiver acesso ao web.config)
 message.To = "vitorrubio@gmail.com"; //e-mail do destinatário, deve vir de um textbox
 message.Subject = "teste 1"; //assunto, deve vir de um textbox, ou do web.config
 message.Body = "Isto é uma mensagem de teste."; //corpo da mensagem, deve vir de um textbox

 //aqui eu configuro os parametros do servidor de SMTP SEM AUTENTICAÇÃO
 SmtpMail.SmtpServer = "[[servidor]]"; //servidor de smtp, deve vir do web.config (mas pode ser  fixo se for uma unica pagina de fale conosco e você não tiver acesso ao web.config)
  
 SmtpMail.Send(message);

 Label1.Text = "e-mail enviado com sucesso!";
}
catch (Exception ex)
{
 Label1.Text = "Erro ao enviar e-mail " + ex.Message;

 //concatena todas as inner exceptions:

 //loop para concatenar todas as exceptions ao longo do caminho, porque a exception mais externa não é muito conclusiva
 while (ex.InnerException != null)
 {
  ex = ex.InnerException;
  Label1.Text += " --- Inner Exception --- " + ex.ToString();
 }
}
Repare bem que no catch eu coloco a mensagem de erro e o exception mais externo no label, mas eu crio um laço while para concatenar as mensagens de todos os exceptions mais internos. Faço o loop enquanto a minha exception corrente EX tiver um inner exception diferente de null. Essa é minha condição de parada. Depois eu substituo o proprio EX pelo inner exception dele mesmo, para que eu não entre num loop infinito.
Com todas essas excessões mostradas a mim eu posso saber o motivo exato de o e-mail não ter sido enviado. É necessário um inglês mínimo.
Agora se você estiver tentando mandar e-mail através de um servidor autenticado, como Terra ou Yahoo, assim você não vai conseguir. Terá de usar alguns artifícios e preencher alguns campos especiais que a Microsoft preparou no objeto message. Você confere isso na listagem 2.
Listagem 1:

MailMessage message = new MailMessage();
try
{
 //crio o objeto MailMessage, que contem o conjunto de parametros de uma mensagem de e-mail

 //aqui eu configuro os parâmetros da mensagem em si
 message.From = "[remetente]"; //e-mail do remetente, deve vir do web.config
 message.To = "vitor@rt.com.br"; //e-mail do destinatário, deve vir de um textbox
 message.Subject = "teste 1"; //assunto, deve vir de um textbox, ou do web.config
 message.Body = "Isto é uma mensagem de teste."; //corpo da mensagem, deve vir de um textbox

 //aqui eu configuro os parametros do servidor de SMTP. A autenticação você pode ver logo abaixo
 SmtpMail.SmtpServer = "[servidor de smtp]"; //servidor de smtp, deve vir do web.config


 /*
  * Mas, se você precisar de mandar um e-mail num servidor smtp com autenticação....
  * num servidor que não é seu.... aí você vai precisar dessa gambiarra da microsoft
 */


 //se você precisar enviar e-mail através de um servidor com autenticação, por exemplo terra ou yahoo, utilize esses parametros
 message.Fields["http://schemas.microsoft.com/cdo/configuration/smtsperver"] = "[servidor de smtp]"; //server
 message.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"] = 25;//porta, geralmente é a 25 quando não usa ssl
 message.Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2;
 message.Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1; //marca se tem que autenticar
 message.Fields["http://schemas.microsoft.com/cdo/configuration/sendusername"] = "[seu login]"; //user
 message.Fields["http://schemas.microsoft.com/cdo/configuration/sendpassword"] = "[sua senha]"; //senha


 SmtpMail.Send(message);

 Label1.Text = "e-mail enviado com sucesso!";
}
catch (Exception ex)
{
 Label1.Text = "Erro ao enviar e-mail " + ex.Message;

 //concatena todas as inner exceptions:

 while (ex.InnerException != null)
 {
  ex = ex.InnerException;
  Label1.Text += " --- Inner Exception --- " + ex.ToString();
 }
} 
 


Observe aqui que
preenchemos alguns campos especiais do objeto Message. Você pode, inclusive, colocar todo o código numa única página .aspx sem precisar de um codebehind. Você não precisa nem de visual studio ou #develop para fazer essa página, qualquer bloco de notas resolve. Veja como fica no proximo snippet:



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >

<html>
<head>
 <title>MandaEmailDireto</title>
 <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
 <meta name="CODE_LANGUAGE" Content="C#">
 <meta name=vs_defaultClientScript content="JavaScript">
 <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body >

 <form id="Form1" method="post" runat="server">
<P>
 <asp:Label id=Label1 runat="server">Label</asp:Label></P>
<P>

<asp:Button style="Z-INDEX: 0" id=Button1 runat="server" Text="Button"></asp:Button></P>
 <script language=C# runat=server>

public void Page_Load(object sender, System.EventArgs e)
{
Response.Write("Página Carregada!<br>");
}

override protected void OnInit(EventArgs e)
{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
base.OnInit(e);
}

public void Button1_Click(object sender, System.EventArgs e)
{

System.Web.Mail.MailMessage message = new System.Web.Mail.MailMessage();
try
{
 //crio o objeto MailMessage, que contem o conjunto de parametros de uma mensagem de e-mail

 //aqui eu configuro os parâmetros da mensagem em si
 message.From = "[remetente]"; //e-mail do remetente, deve vir do web.config
 message.To = "[destinatario]"; //e-mail do destinatário, deve vir de um textbox
 message.Subject = "teste 1"; //assunto, deve vir de um textbox, ou do web.config
 message.Body = "Isto é uma mensagem de teste."; //corpo da mensagem, deve vir de um textbox

 //aqui eu configuro os parametros do servidor de SMTP SEM AUTENTICAÇÃO
 System.Web.Mail.SmtpMail.SmtpServer = "[servidor]"; //servidor de smtp, deve vir do web.config


 /*
  * Mas, se você precisar de mandar um e-mail num servidor smtp com autenticação....
  * num servidor que não é seu.... aí você vai precisar dessa gambiarra da microsoft
 */


 //se você precisar enviar e-mail através de um servidor com autenticação, por exemplo terra ou yahoo, utilize esses parametros
 message.Fields["http://schemas.microsoft.com/cdo/configuration/smtsperver"] = "[servidor]"; //server
 message.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"] = 25;//porta, geralmente é a 25 quando não usa ssl
 message.Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2;
 message.Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1; //marca se tem que autenticar
 message.Fields["http://schemas.microsoft.com/cdo/configuration/sendusername"] = "[login]"; //user
 message.Fields["http://schemas.microsoft.com/cdo/configuration/sendpassword"] = "[senha]"; //senha


 System.Web.Mail.SmtpMail.Send(message);

 Label1.Text = "e-mail enviado com sucesso!";
}
catch (Exception ex)
{
 Label1.Text = "Erro ao enviar e-mail " + ex.Message;

 //concatena todas as inner exceptions:

 while (ex.InnerException != null)
 {
  ex = ex.InnerException;
  Label1.Text += " --- Inner Exception --- " + ex.ToString();
 }
}
} 
 </script>


  </form>

</body>
</html>
Atente que para esses casos de servidores de SMTP autenticados, e até mesmo para alguns casos de servidores de SMTP anônimos do seu próprio domínio, o servidor pode exigir que o domínio do remetente seja o mesmo domínio dele. Ou seja, para mandar um e-mail pelo SMTP do yahoo, o remetente precisa ser do yahoo (não que o yahoo seja assim, isso é só um exemplo).
Não precisamos preencher todos esses dados especiais na mensagem no .Net 2.0.
O que precisamos é instanciar um objeto SMTPClient e preencher corretamente os valores das propriedades.
Vamos ver como fazer no próximo snippet:
  protected void Button1_Click(object sender, EventArgs e)
{
SmtpClient smtpCliente = new SmtpClient();
MailMessage message = new MailMessage();
try
{
 //duas variáveis MailAddress para o remetente e destinatário
 MailAddress fromAdress = new MailAddress("***remetente***", "nome do remetente"); //remetente
 MailAddress toAdress = new MailAddress("***destinatario 1 ****", "nome"); //destinatario 1
 MailAddress toAdress2 = new MailAddress("**destinatario 2 ***", "nome"); //destinatario 2

 message.From = fromAdress;
 message.To.Add(toAdress); //adiciona o destinatario 1
 message.To.Add(toAdress2); //adiciona o destinatario 2
 message.Subject = "Teste";
 message.Body = "mensagem de teste.";

 //configuração do smtp
 smtpCliente.Host = "***servidor***";

 ////credenciais, ou seja, login e senha. Essa parte não precisa se o servidor web for o proprio servidor de e-mail anonimo, ou se o servidor de e-mail anonimo permitir relay a partir do ip que você estiver tentando mandar.
 smtpCliente.Credentials = new NetworkCredential("***login***", "***senha***");

 smtpCliente.Send(message);
 Label1.Text = "e-mail enviado com sucesso!";
}
catch (Exception ex)
{
 Label1.Text = "Erro ao enviar e-mail " + ex.Message;

 //concatena todas as inner exceptions:

 while (ex.InnerException != null)
 {
  ex = ex.InnerException;
  Label1.Text += " --- Inner Exception --- " + ex.ToString();
 }
}
}
Analogamente podemos fazer o envio de e-mail com o código C# direto na página asp.net, conforme o snippet abaixo:

<%@ Import Namespace="System.Net.Mail" %>
<%@ Import Namespace="System.Net" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title>Untitled Page</title>
</head>
<body>
 <form id="form1" runat="server">
 <div>

     <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
     <br />
     <br />
     <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
  
     <script language="C#" runat="server">
  
         protected void Page_Load(object sender, EventArgs e)
         {
             Response.Write("Página Carregada!");
         }
         protected void Button1_Click(object sender, EventArgs e)
         {
             SmtpClient smtpCliente = new SmtpClient();
             MailMessage message = new MailMessage();
             try
             {
                 //duas variáveis MailAddress para o remetente e destinatário
                 MailAddress fromAdress = new MailAddress("email do remetente", "nome do remetente"); //remetente
                 MailAddress toAdress = new MailAddress("destinatario 1", "nome"); //destinatario 1
                 MailAddress toAdress2 = new MailAddress("destinatario 2", "nome"); //destinatario 2

                 message.From = fromAdress;
                 message.To.Add(toAdress); //adiciona o destinatario 1
                 message.To.Add(toAdress2); //adiciona o destinatario 2
                 message.Subject = "Teste";
                 message.Body = "mensagem de teste.";

                 //configuração do smtp
                 smtpCliente.Host = "servidor";
              
                 //credenciais, ou seja, login e senha. Essa parte não precisa se o servidor web for o proprio servidor de e-mail anonimo, ou se o servidor de e-mail anonimo permitir relay a partir do ip que você estiver tentando mandar.
                 smtpCliente.Credentials = new NetworkCredential("login", "senha");

                 smtpCliente.Send(message);
                 Label1.Text = "e-mail enviado com sucesso!";
             }
             catch (Exception ex)
             {
                 Label1.Text = "Erro ao enviar e-mail:<br/> " + ex.Message;

                 //concatena todas as inner exceptions:

                 while (ex.InnerException != null)
                 {
                     ex = ex.InnerException;
                     Label1.Text += " --- Inner Exception --- " + ex.ToString();
                 }
             }
         }
     </script>

 </div>
 </form>
</body>
</html>
Onde quero chegar com tudo isso? Seguinte, para os web designers, que muitas vezes não são programadores e sabem apenas o básico, pode ser um desafio mandar um e-mail
pelo smtp do servidor, seja para um formulario de contato, fale conosco ou até mesmo cadastro. Por isso resolvi criar essa página como uma espécie de template
para que possa ser usada por webdesigners.
Abaixo você pode conferir todo o código desse template de envio de e-mail, com diversos camposde informações gerais, através de um script C# em uma página asp.net, com runat=server

<%@ Import Namespace="System.Net.Mail" %>
<%@ Import Namespace="System.Net" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title>Fale Conosco</title>
</head>
<body>
 <form id="form1" runat="server">
 <div>

     <asp:Label ID="lbMensagem" runat="server" ForeColor="#FF3300"></asp:Label>
     <br />
     <br />
     <asp:Label ID="Label2" runat="server" Text="Nome"></asp:Label>
     <br />
     <asp:TextBox ID="txtNome" runat="server"></asp:TextBox>
     <br />
     <asp:Label ID="Label3" runat="server" Text="E-Mail"></asp:Label>
     <br />
     <asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
     <br />
     <asp:Label ID="Label4" runat="server" Text="Assunto"></asp:Label>
     <br />
     <asp:TextBox ID="txtAssunto" runat="server"></asp:TextBox>
     <br />
     <br />
     <asp:CheckBox ID="cbFumante" runat="server" Text="Fumante" />
     <br />
     <asp:CheckBox ID="cbConducao" runat="server" Text="Condução própria" />
     <br />
     <asp:CheckBox ID="cbSolteiro" runat="server" Text="Solteiro" />
     <br />
     <asp:RadioButtonList ID="rgSexo" runat="server">
         <asp:ListItem Selected="True">Masculino</asp:ListItem>
         <asp:ListItem>Feminino</asp:ListItem>
     </asp:RadioButtonList>
     <br />
     <br />
     <br />
     <asp:Label ID="Label5" runat="server" Text="Corpo da Mensagem"></asp:Label>
     <br />
     <asp:TextBox ID="txtCorpo" runat="server" Height="138px" TextMode="MultiLine"
         Width="299px"></asp:TextBox>
     <br />
     <br />
     <asp:Button ID="btEnviar" runat="server" onclick="btEnviar_Click"
         Text="Enviar" />
  
     <script language="C#" runat="server">
  
         protected void Page_Load(object sender, EventArgs e)
         {
             //isso serve simplesmente para saber se o asp.net está funcionando e a página foi carregada corretamente. Depois de testado pode ser omitido.
             Response.Write("Página Carregada!");
         }
         protected void btEnviar_Click(object sender, EventArgs e)
         {
             SmtpClient smtpCliente = new SmtpClient();
             MailMessage message = new MailMessage();
             try
             {
                 //duas variáveis MailAddress para o remetente e destinatário
                 MailAddress fromAdress = new MailAddress(txtEmail.Text, txtNome.Text); //remetente (campos textbox do cliente)
                 MailAddress toAdress = new MailAddress("vitorrubio@gmail.com", "Vitor Rubio"); //destinatario  (quem recebe na empresa)

                 message.From = fromAdress;
                 message.To.Add(toAdress); //adiciona o destinatario
                 message.Subject = txtAssunto.Text;
              
                 //vamos compor o corpo com todas as informações dadas pelo usuário
                 //criamos uma string chamada corpao: (pode ser um stringbuilder, mas precisa de um import de system.text)
              
                 string corpao = "";
              
                 //vamos concatenando (grudando) todas as informações
                 //o operador += concatena as strings. corpao += "laranja" é o mesmo que dizer "corpao recebe o que já estava escrito lá grudado com "laranja"
                 //"\r\n pula uma linha, como se tivesse dado um enter ou escrito um <br> no html
              
                 corpao += "Nome: " + txtNome.Text + "\r\n";
                 corpao += "E-Mail: " + txtEmail.Text + "\r\n";
                 corpao += "Assunto: " + txtAssunto.Text + "\r\n";
              
                 //pulamos mais uma linha
                 corpao += "\r\n";
              
                 //começamos a colocar as outras informações, sobre sexo etc. Essas informações não são strings (palavras ou cadeias de caracteres)
                 //mas são booleanas (lógica), com excessão de sexo que dá para pegar o valor selecionado e transformar em string
                 //entenda string como uma cadeia, ou sequencia, de caracteres, como palavras e frases.
              
                 //aqui concatenamos a palavra "Fumante: " e usamos o operador ternário para perguntar: A caixinha está clicada? Se sim então grude a palavra "sim", se não "não"
                 corpao += "Fumante: " + ((cbFumante.Checked)?"Sim":"Não") + "\r\n";
                 corpao += "Conducao Própria: " + ((cbConducao.Checked)?"Sim":"Não") + "\r\n";
                 corpao += "Solteiro: " + ((cbSolteiro.Checked)?"Sim":"Não") + "\r\n";
              
                 //agora o sexo, que não é nem checkbox nem textbox, mas é um radiogroup
                 corpao += "Sexo: " + rgSexo.SelectedValue.ToString() + "\r\n";
              
                 //pula duas linhas e poe a mensagem:
                 corpao +=  "\r\n\r\n";
                 corpao += txtCorpo.Text + "\r\n";
              
                 //e o body da mensagem é o corpão:
                 message.Body = corpao;
              
                 //facinho facinho!

                 //configuração do smtp
                 smtpCliente.Host = "localhost"; //use  o host fornecido pelo serviço de hospedagem, se precisar armazene no web.config
              
                 //credenciais, ou seja, login e senha. Essa parte não precisa se o servidor web for o proprio servidor de e-mail anonimo, ou se o servidor de e-mail anonimo permitir relay a partir do ip que você estiver tentando mandar.
                 //nesse caso, se usarmos o serviço de SMTP do proprio serviço de hosting/hospedagem/colocation provavelmente será um SMTP anônimo. Consulte seu fornecedor de serviços para tirar as dúvidas.
                 //smtpCliente.Credentials = new NetworkCredential("login", "senha");

                 smtpCliente.Send(message);
              
                 //colocamos, através do dream weaver, expression ou visual studio um label e demos o nome de lbMensagem
                 //usaremos a propriedade text do lbMensagem para avisar o usuario do sucesso ou fracasso do envio do e-mail
              
                 lbMensagem.Text = "e-mail enviado com sucesso!";
             }
             catch (Exception ex)
             {
                 //se der erro, veremos onde
                 lbMensagem.Text = "Erro ao enviar e-mail:<br/> " + ex.Message;

                 //concatena todas as inner exceptions:

                 while (ex.InnerException != null)
                 {
                     ex = ex.InnerException;
                     lbMensagem.Text += " --- Inner Exception --- " + ex.ToString();
                 }
             }
         }
     </script>

 </div>
 </form>
</body>
</html>

Aqui neste arquivo zipado temos vários exemplos do envio de e-mail através do C#
Os exemplos EnviaEmail_1.1 e EnviaEmailDireto_1.1 mostram como enviar e-mail através do .net framework 1.1 com e sem code behind. Ou seja, o "Direto" aqui significa que o código C# está direto na página, para ser compilado e executado em runtime, no server.
Os exemplos EnviaEmail_2.0 e EnviaEmailDireto_2.0 são análogos, mas para .net framework 2.0 ou superior.
Como dito anteriormente, para mandar e-mails a partir do próprio servidor de smtp ele deve estar configurado corretamente, com relay e tudo o mais, e o
destinatário tem que aceitar emails provindos do seu IP. Este Site pode te ajudar a configurar o SMTP.
Esses livros são apenas 3 de milhares que podem te ajudar a iniciar uma carreira de programador C# / Asp.net

http://www.livrariasaraiva.com.br/produto/produto.dll/detalhe?pro_id=130808&ID=C95552527D909041024070050

https://www.verticebooks.com.br/index.php?sub=produto&id=16172

http://www.livrariasaraiva.com.br/produto/produto.dll/detalhe?pro_id=944045&ID=C95552527D909041024070050
Espero que tenha sido util a todos.

have fun ;)



Um comentário:

  1. Vitor procurei este método e entretodos foi este o unico que consegui aplicar. Muito obrigado. Foi uma ajuda enorme!
    Marcos
    mrcmsilva@yahoo.com.br

    ResponderExcluir

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)