segunda-feira, 9 de maio de 2011

Enviando emails com Delphi - Parte II

Há alguns dias, escrevi um post sobre o envio de emails com Delphi, mostrando a configuração básica dos componentes Indy para SMTP e também as funções que devem ser chamadas para completar o processo. No exemplo, a mensagem incluída no email era um texto simples, sem qualquer tipo de formatação.

No começo, os programas leitores de email só conseguiam trabalhar com mensagens assim, onde apenas texto era trocado. É um comportamento básico mas que ainda tem sua utilidade, principalmente quando há questões de segurança envolvidas. Com a evolução da internet, entretanto, praticamente todos os leitores de email conseguem exibir mensagens com formatação rica. Usando HTML podemos compor emails com layouts complexos, usando cores e tipos de fontes diferentes, além da inclusão de imagens, links, tabelas, animações, entre outros. Uma grande vantagem desse formato é que ele já é utilizado para construir os sites da internet. Ou seja, HMTL é uma ferramenta bastante conhecida e amplamente suportada.

Do ponto de vista do envio de email, o que há de diferente em relação ao que foi apresentado no outro post ? Basicamente, apenas dois detalhes. O primeiro é uma propriedade da mensagem que determina o tipo de conteúdo que a mensagem está trafegando. Essa característica é chamada MIME (Multipurpose Internet Mail Extensions, ou Extensões Multipropósito para Correio na Internet). O padrão para essa propriedade no corpo de um email é o valor text/plain, que significa que a mensagem é composta por um texto simples. Como queremos montá-la como um HTML, temos que avisá-la disso:
IdMessage1.ContentType := 'text/html';
IdMessage1.CharSet := 'ISO-8859-1';

Veja que eu também modifiquei o charset da mensagem. Esta propriedade indica qual é o conjunto de caracteres que a mensagem está usando. Como o português usa acentuação, é preferível trocar o padrão americano pelo conjunto latino ('ISO-8859-1').

O outro detalhe é que o corpo da mensagem agora tem que respeitar o MIME configurado. Quero dizer com isso que teremos que montar um HTML para a mensagem:
IdMessage1.Body.Text := '<html><head>' +
'<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">' +
'</head><body>' +
'<p>Essa mensagem é um <b>Teste</b> de email HTML.</p>' +
'</body></html>';

Embora pareça redundante, é importante informar de novo no cabeçalho do HTML quem é o MIME e o charset. Os leitores de email utilizam as informações desse cabeçalho para renderizar a mensagem recebida via SMTP.

E se quisermos incluir uma imagem em nosso HTML ? Algumas pessoas publicam a imagem na internet e referenciam o link dela no HTML da mensagem. Mas essa solução exige que o destinatário esteja conectado para poder buscar a imagem, coisa que nem sempre é verdade. Numa empresa, por exemplo, as mensagens são recebidas de forma centralizada por um servidor de email, dispensando a necessidade de ter internet local. Muitas delas adotam ainda restrições ao acesso à internet.

Uma maneira melhor de se fazer isso é enviar a imagem junto com o HTML. Ao invés de preencher o campo Body da mensagem, teremos que decompô-la em seus constituintes básicos para podermos identificar de forma separada o MIME de cada um. Isto é, o corpo da mensagem é um HTML enquanto a imagem é um arquivo binário com MIME próprio. O conjunto todo terá um MIME especial (multipart/mixed) que sinaliza que a mensagem está montada como múltiplas partes independentes.

Cada parte deverá ser anexada à mensagem através da propriedade MessageParts. Para o corpo, usamos o tipo TIdText. Para a imagem, o tipo tradicional para anexos (TIdAttachmentFile).
var
text : TIdText;
at : TIdAttachmentFile;
begin
IdMessage1.MessageParts.Clear();
IdMessage1.ContentType := 'multipart/mixed';

text := TIdText.Create (IdMessage1->MessageParts, Nil);
text.ContentType := 'text/html';
text.CharSet := 'ISO-8859-1';
text.Body.Text := PreparaHTML();

at := TIdAttachmentFile.Create (IdMessage1->MessageParts,
'C:\\Inetpub\\wwwroot\\winxp.gif');
at.ContentType := 'image/gif';
at.FileName := 'winxp.gif';

IdSMTP1.Connect();
IdSMTP1.Send(IdMessage1);
{ ... }

O HTML pode, então, fazer referência diretamente ao nome do arquivo anexado, sem precisar estipular um endereço na internet. A única coisa é que o nome do arquivo deve ser exatamente igual àquele informado na propriedade FileName do anexo:
function TForm1.PreparaHTML : String;
begin
{ ... }
Result := Result + '<img style="margin:1px 1px 1px 0px;" src="winxp.gif" />';
{ ... }
end;

Em tese, não há restrição a quantos recursos externos podem ser agregados ao email usando esse tipo de construção. Também não se restringe à inclusão de imagens, podendo ser usado para incorporar animações, scripts, folhas de estilo, etc. - desde que tenham os respectivos MIMEs devidamente configurados.

Estou com a versão 10 do Indy que vem com o Delphi XE mas acredito que os recursos mostrados aqui estejam disponíveis em versões anteriores também.

Mais Informações
Enviando emails com Delphi

10 comentários:

  1. TIdText não é reconhecido no delphi 2010, o que faço para substituir ?

    ResponderExcluir
  2. Sou especialista em SI pela UFLA gostaria de fazer uma indicação para sua equipe, tenho um colega na petrobrás que é um gênio em ti, seria interessante aproveitar o conhecimento de todos para melhorar a tecnologia em ti do nosso país.
    um abraço.

    ResponderExcluir
  3. Fábio

    O que exatamente quer dizer com "indicação pra minha equipe" ? Na verdade, o blog hj é apoiado pela ABC71 mas mantido apenas por mim...

    Se a ideia é submeter posts ao blog, toda ajuda é bem-vinda ! Pode remeter o texto ao email do blog e, se for o caso, o publicarei com os devidos créditos.

    []s

    ResponderExcluir
  4. Vicente

    O TidText mudou de lugar. No Indy9, ele estava junto com a unit IdMessage enquanto no Indy10 ele foi deslocado para uma unit própria.

    Isto quer dizer que basta adicionar a unit IdText na cláusula uses do seu fonte para que ele encontre o TIdText.

    []

    ResponderExcluir
  5. Saudações Luís Gustavo.

    Parabéns pelos post's.

    Estou com um probleminha no envio de e-mail.

    Desenvolvi um software em Delphi 2010 com MySql. Nesse software, o cliente deve efetuar um login.

    Acontece que estou tentando implementar uma opção para o cliente de reenvio de senha, caso esse não a lembre.

    Fiz alguns testes com a dupla IdSMTP e TIdMessage. O procedimento é bem simples, pois o servidor tem a opção sem o protocolo SSL. Entretanto quando envio um e-mail, esse e-mail não chega no destino. Também não ocorre nenhuma mensagem de erro ao enviá-lo.

    A porta sugerida pelo site de hospedagem, sem o protocolo SSL, é a 26.

    Através do Outlook 2007 consigo enviar os e-mails normalmente.

    Se você puder me ajudar com alguma ideia, agradeço.

    ResponderExcluir
    Respostas
    1. João

      Você pode criar um log inteceptando a comunicação do idSMTP com o servidor pra ver onde está falhando. Inclua um TIdLogDebug ou um TIdLogFile (ambos estão na guia Indy Intercepts)em seu projeto, vinculando-o à propriedade Intercept do idSMTP.

      []s

      Excluir
  6. Caro Luís Gustavo.

    Obrigado pela dica.

    Gerei o log, como você sugeriu.

    Parece que tudo correu bem. Mas, de qualquer forma vou postar a mensagem.

    Por questões éticas não coloquei o nome do provedor e dos e-mail's. o que estiver em parêntesis foi alterado.


    Stat Connected.
    Recv 10/02/2012 22:45:28: 220-br54.(PROVEDOR) ESMTP Exim 4.69 #1 Fri, 10 Feb 2012 22:45:31 -0200 220-We do not authorize the use of this system to transport unsolicited, 220 and/or bulk e-mail.
    Sent 10/02/2012 22:45:28: EHLO TeCMaisComptud
    Recv 10/02/2012 22:45:28: 250-br54.(PROVEDOR) Hello TeCMaisComptud [(IP)]250-SIZE 52428800250-PIPELINING250-AUTH PLAIN LOGIN250-STARTTLS250 HELP
    Sent 10/02/2012 22:45:28: AUTH LOGIN
    Recv 10/02/2012 22:45:28: 334 VXNlcm5hbWU6
    Sent 10/02/2012 22:45:28: c2VkaW1AZGF0YWxvZ3VlLmNvbS5icg==
    Recv 10/02/2012 22:45:28: 334 UGFzc3dvcmQ6
    Sent 10/02/2012 22:45:28: NjU3MjMyNDM5ODk=
    Recv 10/02/2012 22:45:29: 235 Authentication succeeded
    Sent 10/02/2012 22:45:29: RSET
    Recv 10/02/2012 22:45:29: 250 Reset OK
    Sent 10/02/2012 22:45:29: MAIL FROM: <(E-MAIL)>
    Recv 10/02/2012 22:45:29: 250 OK
    Sent 10/02/2012 22:45:29: RCPT TO:<(E-MAIL)>
    Recv 10/02/2012 22:45:29: 250 Accepted
    Sent 10/02/2012 22:45:29: DATA
    Recv 10/02/2012 22:45:29: 354 Enter message, ending with "." on a line by itself
    Sent 10/02/2012 22:45:29: From: "(E-MAIL)" <(E-MAIL)>Subject: TesteTo: (E-MAIL)MIME-Version: 1.0Date: Fri, 10 Feb 2012 22:45:29 -0200
    Sent 10/02/2012 22:45:29: Content-Type: text/html
    Sent 10/02/2012 22:45:29:
    Sent 10/02/2012 22:45:29: Content-Transfer-Encoding: quoted-printable
    Sent 10/02/2012 22:45:29: Content-Disposition: inline
    Sent 10/02/2012 22:45:29:
    Sent 10/02/2012 22:45:29:
    Sent 10/02/2012 22:45:29: teste
    Sent 10/02/2012 22:45:29:
    Sent 10/02/2012 22:45:29: .
    Recv 10/02/2012 22:45:30: 250 OK id=1Rw15p-0006j5-Hd
    Sent 10/02/2012 22:45:30: QUIT
    Recv 10/02/2012 22:45:30: 221 br54.(PROVEDOR) closing connection
    Stat Disconnected.

    ResponderExcluir
    Respostas
    1. João

      Aparentemente o envio foi mesmo feito corretamente. Não conheço muito do gerenciamento do servidor de email mas creio que seja possível incluir nele regras que podem estar redirecionando ou barrando seu email.

      Verifique se não há regras estipulando, por exemplo, que apenas emails de remementes confiáveis são entregues. Por causa disso, suas mensagens podem ter sido incluídas na caixa de spam.

      []s

      Excluir
  7. Olá Luís Gustavo, estava já há algum tempo procurando uma solução para montar e-mails com imagens e agora encontrei a solução com as suas dicas. Obrigado e parabéns !!!
    Eduardo Flaeschen

    ResponderExcluir
  8. Olá Luís Gustavo, estava procurando já há algum tempo uma solução para o envio de e-mails com imagens e encontrei nessa sua publicação, muito simples e eficiente. Parabéns e obrigado.

    ResponderExcluir

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.