News & Events
[Tutorial] Como enviar e-mail pelo Gmail com Delphi 10.2 Tokyo e OpenSSL?
- 5 de maio de 2017
- Posted by: Adriano Santos
- Category: Notícias
![](http://portal.tdevrocks.com.br/wp-content/uploads/2017/05/delphigmailopenssl.png)
A internet está recheada de métodos [e também componentes] que prometem enviar e-mail através de nossos softwares desenvolvidos em Delphi, isso é certo. Entretanto sempre recebo pedidos para registrar aqui um método eficaz para construir nossas próprias rotinas. Lutei muito para não publicar nada nesse sentido, haja vista que há, como já mencionei, vários canais na internet que possuem tais functions. Eu já uso um método próprio para envio de correio eletrônico via minhas aplicações, mas minha function estava incompleta. Não enviava em formato HTML e tão pouco com anexos. Resolvi então criar um tutorial completo e deixar aqui registrado.
Andei, andei, andei até encontrar. Parece uma canção [e o pior que é uma canção mesmo – Andei, andei, andei até encontrar, Chitãozinho & Chororó, ;)], mas foi o que aconteceu. Testei várias funções até chegar em um canal muito bom. Meu método de envio estava funcionando perfeitamente como mencionei, mas era usado apenas com os e-mails da empresa, que não precisam de SSL.
Como enviar e-mail pelo Gmail com Delphi 10 e OpenSSL
Enviar mensagens de e-mail utilizando alguns servidores muitas vezes é uma tarefa não muito fácil. Isso porque alguns servidores, como o Gmail por exemplo, é necessário utilizar autenticação, isso significa que você precisa carregar a DLL OpenSSL, é esse o tema que vamos abordar aqui. Eu disse acima que encontrei um canal legal que aborta isso, certo? Pois bem, o canal é o blog do MVP André Celestino. Além desse artigo existem muitos outros bons artigos de assuntos que tenho certeza, te ajudarão muito. Muito bom, chega de história.
Nosso objetivo nesse tutorial é: Criar uma função para enviar e-mails usando o Gmail com OpenSSL, em formato HTML e como bônus, vamos guardar as configurações em arquivo de inicialização INI. Vamos lá:
Abra seu Delphi 10.2 Tokyo e crie uma nova aplicação VCL (Visual Component Library) usando o menu File > New > VCL Forms Application – Delphi. Desenhe um form semelhante ao mostrado logo abaixo:
Perceba que inserimos campos bem básicos para o envio das mensagens. O anexo será único, portanto se você quiser implementar o envio de mais de um arquivo anexo, terá que alterar a função, mas isso é fácil. Também não colocamos aqui as configurações de envio, tais como: usuário, senha, endereço de SMTP, entre outros. Isso ficará armazenado em um arquivo INI que criaremos mais abaixo. Para esse início, renomeie os componentes:
- edtPara;
- edtAssunto;
- memCorpo;
- edtAnexo.
O segundo componente, como deve ter notado, é um componente do tipo Memo. O restante dos botões e labels não são necessárias alterações em propriedades. Salve o projeto, faça um primeiro Build e execute, apenas para forçar a criação do caminho de saída desse projeto. Lembre-se, por default o Delphi cria o executável final do nosso projeto em um caminho semelhante a Caminho_Do_Projeto\Win32\Debug…
Isso é importante porque agora teremos que criar um arquivo INI e ele deverá ser salvo no mesmo local onde o executável será criado. A estrutura de nosso INI é bem simples, veja:
From=minhaconta@gmail.com
BccList=copiaoculta@dominio.com
Host=smtp.gmail.com
Port=465
Username=minhaconta@gmail.com
Password=SENHA
A explicação é bem simples. Criamos uma seção chamada EMAIL e nela criamos algumas chaves. São elas:
- From: E-mail de onde está partindo a mensagem. Isso aparecerá no WebMail ou Outlook do destinatário;
- BccList: Lista de e-mails destinatários que receberão como cópia oculta. Não é obrigatório, válido apenas como didática;
- Host: Servidor SMTP, nesse caso do Google;
- Port: Porta usada pelo SMTP para envio;
- Username: Usuário de autenticação do serviço, geralmente é o mesmo que o From, mas não é obrigatório que seja o mesmo;
- Password: A senha para autenticação.
Aqui criei em inglês as chaves, mas fica a seu critério. Salve esse arquivo com o nome Config.ini no diretório onde o arquivo executável do exemplo se encontra.
Declarando as Uses
Nesse exemplo optei por não ter os componentes Indy no próprio formulário, ou seja, criarei todos em runtime. Entretanto as Units relacionadas a cada componente e aos métodos utilizados para envio, precisam ser declaradas. Para isso acesse a cláusula Uses na seção Interface do formulário e declare as Units abaixo:
...
//Units Necessárias
IniFiles,
IdComponent,
IdTCPConnection,
IdTCPClient,
IdHTTP,
IdBaseComponent,
IdMessage,
IdExplicitTLSClientServerBase,
IdMessageClient,
IdSMTPBase,
IdSMTP,
IdIOHandler,
IdIOHandlerSocket,
IdIOHandlerStack,
IdSSL,
IdSSLOpenSSL,
IdAttachmentFile,
IdText;
Tem apenas uma Unit intrusa nessa lista. A Unit IniFiles utilizada para ter acesso a leitura e gravação de arquivos de inicialização INI. Feito isso, crie um método em Private como abaixo:
function EnviarEmail(const AAssunto, ADestino, AAnexo: String; ACorpo: TStrings): Boolean;
A função possui como parâmetro AAssunto, ADestino, AAnexo e ACorpo. Ficou fácil saber o que cada um signfica certo? O parâmetro final, ACorpo, criei do tipo TStrings, isso porque podemos ter mais de uma linha de texto, por isso a escolha dessa classe. Nós poderemos também enviar para esse parâmetro nosso texto em formato HTML, ou seja, entre tags e o e-mail chegará formatado como tal.
Excelente, preessione Ctrl + Shift + C para criar o escopo da função. O código completo da função você verá logo abaixo. Copie o código e cole em seu Delphi, ou baixe o código-fonte completo no repositório GitHub do TDevRocks.
function TfrmPrincipal.EnviarEmail(const AAssunto, ADestino, AAnexo: String; ACorpo: TStrings): Boolean;
var
IniFile : TIniFile;
sFrom : String;
sBccList : String;
sHost : String;
iPort : Integer;
sUserName : String;
sPassword : String;
idMsg : TIdMessage;
IdText : TIdText;
idSMTP : TIdSMTP;
IdSSLIOHandlerSocket : TIdSSLIOHandlerSocketOpenSSL;
begin
try
try
//Criação e leitura do arquivo INI com as configurações
IniFile := TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'Config.ini');
sFrom := IniFile.ReadString('Email' , 'From' , sFrom);
sBccList := IniFile.ReadString('Email' , 'BccList' , sBccList);
sHost := IniFile.ReadString('Email' , 'Host' , sHost);
iPort := IniFile.ReadInteger('Email', 'Port' , iPort);
sUserName := IniFile.ReadString('Email' , 'UserName' , sUserName);
sPassword := IniFile.ReadString('Email' , 'Password' , sPassword);
//Configura os parâmetros necessários para SSL
IdSSLIOHandlerSocket := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
IdSSLIOHandlerSocket.SSLOptions.Method := sslvSSLv23;
IdSSLIOHandlerSocket.SSLOptions.Mode := sslmClient;
//Variável referente a mensagem
idMsg := TIdMessage.Create(Self);
idMsg.CharSet := 'utf-8';
idMsg.Encoding := meMIME;
idMsg.From.Name := 'MEU ASSUNTO';
idMsg.From.Address := sFrom;
idMsg.Priority := mpNormal;
idMsg.Subject := AAssunto;
//Add Destinatário(s)
idMsg.Recipients.Add;
idMsg.Recipients.EMailAddresses := ADestino;
idMsg.CCList.EMailAddresses := 'PARA@DOMINIO.COM.BR';
idMsg.BccList.EMailAddresses := sBccList;
idMsg.BccList.EMailAddresses := 'PARA@DOMINIO.COM.BR'; //Cópia Oculta
//Variável do texto
idText := TIdText.Create(idMsg.MessageParts);
idText.Body.Add(ACorpo.Text);
idText.ContentType := 'text/html; text/plain; charset=iso-8859-1';
//Prepara o Servidor
IdSMTP := TIdSMTP.Create(Self);
IdSMTP.IOHandler := IdSSLIOHandlerSocket;
IdSMTP.UseTLS := utUseImplicitTLS;
IdSMTP.AuthType := satDefault;
IdSMTP.Host := sHost;
IdSMTP.AuthType := satDefault;
IdSMTP.Port := iPort;
IdSMTP.Username := sUserName;
IdSMTP.Password := sPassword;
//Conecta e Autentica
IdSMTP.Connect;
IdSMTP.Authenticate;
if AAnexo <> EmptyStr then
if FileExists(AAnexo) then
TIdAttachmentFile.Create(idMsg.MessageParts, AAnexo);
//Se a conexão foi bem sucedida, envia a mensagem
if IdSMTP.Connected then
begin
try
IdSMTP.Send(idMsg);
except on E:Exception do
begin
ShowMessage('Erro ao tentar enviar: ' + E.Message);
end;
end;
end;
//Depois de tudo pronto, desconecta do servidor SMTP
if IdSMTP.Connected then
IdSMTP.Disconnect;
Result := True;
finally
IniFile.Free;
UnLoadOpenSSLLibrary;
FreeAndNil(idMsg);
FreeAndNil(IdSSLIOHandlerSocket);
FreeAndNil(idSMTP);
end;
except on e:Exception do
begin
Result := False;
end;
end;
end;
Vamos a algumas explicações. Abaixo a seção var da função. Primeiro nós declaramos uma variável IniFile para efetuar a leitura dos dados do arquivo INI. As variáveis logo abaixo são responsáveis por receber as informações do arquivo INI. Usaremos o método ReadString para efetuar a leitura desses dados.
var
IniFile : TIniFile;
sFrom : String;
sBccList : String;
sHost : String;
iPort : Integer;
sUserName : String;
sPassword : String;
idMsg : TIdMessage;
IdText : TIdText;
idSMTP : TIdSMTP;
IdSSLIOHandlerSocket : TIdSSLIOHandlerSocketOpenSSL;
Na sequência estão as variáveis relacionadas aos componentes usados para envio das mensagens. São eles o idMsg do tipo TIdMessage para envio compor a mensagem. A variável idText do tipo TidText é usada para configurar o corpo da mensagem que pode ser formatada em HTML como já mencionado. Em seguida declaramos idSMTP usada para conectar-se ao servidor de envio e efetivame te enviar a mensagem. Por fim, idSSLIOHandlerSocket responsável por autenticar a conexão usando servidores seguros, SSL.
idMsg : TIdMessage;
idText : TIdText;
idSMTP : TIdSMTP;
idSSLIOHandlerSocket : TIdSSLIOHandlerSocketOpenSSL;
Vamos para o corpo da função. Começamos lendo e inicializando as variáveis do arquivo INI. Em seguida configuramos as opções de SSL na variável idSSLIOHandlerSocket. As próximas linhas nós inicializamos e configuramos tudo que é relacionado a mensagem em si, ou seja, configuramos o componente [variável na verdade] idMsg. Perceba que criamos uma instância da variável e configuramos suas propriedades. Não entrarei em detalhes sobre todas elas, até mesmo porque o help do Delphi é bastate completo nesse sentido. Vejamos algumas delas:
- From.Name: Nome da pessoa que enviou o e-mail;
- From.Address: Endereço de origem;
- Priority: Prioridade da mensagem;
- Subject: Assunto da mensagem;
Em seguuida configuramos as listas de Destinatários [Recipients], Cópias [CCList] e Cópias Ocultas [BCCList]. Evidentemente que as duas últimas são opcionais. Como exemplo, estamos carregando uma BBCList da variável sBccList que veio do arquivo INI.
//Variável referente a mensagem
idMsg := TIdMessage.Create(Self);
idMsg.CharSet := 'utf-8';
idMsg.Encoding := meMIME;
idMsg.From.Name := 'MEU ASSUNTO';
idMsg.From.Address := sFrom;
idMsg.Priority := mpNormal;
idMsg.Subject := AAssunto;
//Add Destinatário(s)
idMsg.Recipients.Add;
idMsg.Recipients.EMailAddresses := ADestino;
idMsg.CCList.EMailAddresses := 'PARA@DOMINIO.COM.BR';
idMsg.BccList.EMailAddresses := sBccList;
idMsg.BccList.EMailAddresses := 'PARA@DOMINIO.COM.BR'; //Cópia Oculta
A variável idText é responsável pelo corpo da mensgem que será enviada. Ela receberá o conteúdo do parâmetro ACorpo da nossa function. Atenção para algo realmente importante aqui. A propriedade ContentType precisa possuir as configurações necessárias para o tipo de formatação que será usado para nossa mensagem. Usamos a “formatação” ‘text/html; text/plain; charset=iso-8859-1’ que significa que os e-mails enviados poderão ter formatação comum
text language="plain/text"
, em HTML
text language="html/text"
e ainda conterão acentos e caracteres especiais [charset=iso-8859-1], do contrário nossos acentos sairão codificados em códigos HTML.
//Variável do texto
idText := TIdText.Create(idMsg.MessageParts);
idText.Body.Add(ACorpo.Text);
idText.ContentType := 'text/html; text/plain; charset=iso-8859-1';
Por fim configuramos o componente idSMTP que é responsável por enviar a mensagem em si. Aqui todas as configurações são extremamente importantes, mas vamos a explicações específicas. A propriedade IOHandler precisa ser vinculada ao componente SSL para poder conseguir autenticação com o servidor do Google. Também é importante configurar as propriedades UserTLS e AuthType como vimos. Por fim, host [Servidor de SMTP], Port [Porta] e ainda Usuário e Senha [Username e Password].
//Prepara o Servidor
idSMTP := TIdSMTP.Create(Self);
idSMTP.IOHandler := IdSSLIOHandlerSocket;
idSMTP.UseTLS := utUseImplicitTLS;
idSMTP.AuthType := satDefault;
idSMTP.Host := sHost;
idSMTP.AuthType := satDefault;
idSMTP.Port := iPort;
idSMTP.Username := sUserName;
idSMTP.Password := sPassword;
Fazemos então a conexão [Connect] e autenticação [Authenticate] com o servidor do Google. Na linha seguinte verificamos se há anexo e invocamos a classe TIdAttachmetFile para incluir o arquivo. Caso precise inserir mais de um arquivo, você precisará criar uma rotina capaz de invovar o .Create da classe para cada arquivo. Fica a seu critério.
if AAnexo <> EmptyStr then
if FileExists(AAnexo) then
TIdAttachmentFile.Create(idMsg.MessageParts, AAnexo);
O retante do código é bem fácil de entender. Verificamos se a conexão com o servidor ocorreu e em caso positivo invocamos o método Send do componente idSMTP para enviar definitivamente a mensagem. Em caso de erro, exibimos uma mensagem. Na sequência desconectamos do servidor e liberamos as variáveis de memória.
//Se a conexão foi bem sucedida, envia a mensagem
if idSMTP.Connected then
begin
try
IdSMTP.Send(idMsg);
except on E:Exception do
begin
ShowMessage('Erro ao tentar enviar: ' + E.Message);
end;
end;
end;
//Depois de tudo pronto, desconecta do servidor SMTP
if idSMTP.Connected then
idSMTP.Disconnect;
Result := True;
finally
IniFile.Free;
UnLoadOpenSSLLibrary;
FreeAndNil(idMsg);
FreeAndNil(idSSLIOHandlerSocket);
FreeAndNil(idSMTP);
end;
Chamando o método de envio
Precisamos chamar o método de envio passando como parâmetro as informações pertinentes. Para isso acesse o evento OnClick do botão Enviar e codifique. É bem simples fazer isso, haja vista que precisamos apenas chamar a function passando os parâmetros. Esses parâmetros serão capturados dos objetos visuais, edtPara, edtAssunto, memCorpo e edtAnexo.
if EnviarEmail(edtAssunto.Text, edtPara.Text, edtAnexo.Text, memCorpo.Lines)
then ShowMessage('Enviado com sucesso!')
else ShowMessage('Não foi possível enviar o e-mail!');
Fazemos apenas uma verificação para saber se o método conseguiu ou não enviar o e-mail.
Configuração adicional
Em nosso exemplo utilizamos autenticação por SSL nos servidores do Google. Entretanto para isso não basta colocarmos os componentes corretos em tela. Precisamos ainda das DLLs referentes ao uso de SSL. São elas libeay32.dll e ssleay32.dll que podem facilmente serem encontradas nesse link. Essas foram testadas na família XE do Delphi, inclusive com a versão Tokyo, atual versão até o fechamento dessa publicação.
Você também pode encontrar essas DLL baixando o código final desse artigo. Elas estão na pasta Debug do projeto. Precisam ficar armazenadas no mesm diretório do executável.
Pegando carona do artigo do André Celestino
O André Celestino, citado no início do artigo, dá ainda ainda dicas muito legais e por isso o crédito aqui vai todo para ele. Abaixo alguns bônus deixados por Ele em seu artigo.
Bônus 1. Para enviar um e-mail formtado em HTML, basta utilizar o objeto idText no exemplo acima e inserir as tags da linguagem:
IdText := TIdText.Create(IdMessage.MessageParts);
IdText.Body.Add('<html>');
IdText.Body.Add('<body>');
IdText.Body.Add('<h1><font color='red'> Teste Formatação em HTML </font></h1>');
IdText.Body.Add('</body>');
IdText.Body.Add('</html>');
IdText.ContentType := 'text/html; charset=iso-8859-1';
Bônus 2. Caso esteja utilizando o servidor Terra, utilize as configurações a seguir (colaboração do leitor Ricardo Silva):
// Configuração do SMTP
IdSMTP.AuthenticationType := atLogin;
IdSMTP.Port := 587;
IdSMTP.Host := 'smtp.sao.terra.com.br';
IdSMTP.Username := 'usuario@terra.com.br';
IdSMTP.Password := 'senha';
Bônus 3. Aproveitando a dica acima, confira também as configurações do servidor do Office365:
// Configuração do SSL
IdSSLIOHandlerSocket.SSLOptions.Method := sslvTLSv1;
IdSSLIOHandlerSocket.PassThrough := True;
IdSSLIOHandlerSocket.SSLOptions.Mode := sslmServer;
// Configuração do SMTP
IdSMTP.IOHandler := IdSSLIOHandlerSocket;
IdSMTP.AuthenticationType := atLogin;
IdSMTP.Port := 587;
IdSMTP.Host := 'smtp.office365.com';
IdSMTP.Username := 'usuario';
IdSMTP.Password := 'senha';
Conclusão
Como pudemos ver acima, existe um certo grau de dificuldade para se enviar mensagens de e-mail utilizando Gmail e OpenSSL, mas nada é impossível. Esperamos que essa dica tenha sido importante para você e que o aproveitamento tenha sido satisfatório. Gostou do artigo? Então clique no Like acima e compartilhe em suas redes sociais.
Muito obrigado, bons estudos e até a próxima.
![foto](http://www.tdevrocks.com.br/wp-content/uploads/2016/11/adriano-santos.png)