Envio de E-Mails no Delphi Win32
Veja neste artigo de Daniel Wildt como enviar e-mais com o Delphi, a partir da tecnologia MAPI.
Envio de E-Mails no Delphi Win32
Desafio – Clientes MAPI
O envio de emails sempre é um recurso necessário nas aplicações de hoje, sejam estas cliente/servidor, multicamadas. O e-mail é uma ferramenta excelente para notificar usuários, realizar envio de informações programadas e com o uso principal, permitir a comunicação entre pessoas! J
Primeiro vamos ao básico!
A forma mais simples de se programar um envio de email é utilizando funções como a ShellExecute, disponível na unit ShellAPI. Vamos ao primeiro exemplo. Abra o menu “Iniciar”/”Start” do Windows e acesse a opção “Executar”/”Run”. Ali digite mailto:emailteste@email.com e aperte o botão “OK”. Você vai verificar que o Windows vai procurar pelo cliente de e-mail configurado no seu computador para realizar o envio do email. Quanto a isto não importa qual o programa utilizado, OutlookExpress, Eudora, Outlook ou Mozilla ThunderBird por exemplo.
A principal questão de se querer fazer uso do cliente de email já instalado é a questão do histórico de mensagens. Sem isto, você precisaria ter na sua aplicação uma tabela para armazenar os emails enviados pelo usuário do sistema. Usando MAPI não temos este problema, pois estamos nos comunicando com o cliente de email do sistema.
Hein? MAPI? O que é isto? MAPI significa Messaging Application Programming Interface! É uma API com uma série de funcionalidades para se realizar por exemplo o envio de e-mails! Usando a API do Windows, fazemos uses da unit MAPI e utilizamos estruturas como TMapiMessage, TMapiRecipDesc e PMapiFileDesc. Depois de tudo utilizamos a função MapiSendMail e com o retorno podemos tratar um erro ocorrido no envio da mensagem.
Parece difícil né? Bom, usar API do Windows sempre complica no início, até que se tenha domínio das mensagens, estruturas e funções a serem utilizadas. Veremos neste artigo como facilitar o uso e não cair direto na API do Windows.
Usando o ShellExecute para envio de E-Mail
Para o primeiro exemplo iremos montar uma tela para realizar um envio de mensagem, como se fosse uma caixa de nova mensagem do cliente de e-mail utilizado no seu sistema.
Veja a Figura 1 com uma tela da aplicação montada. Temos um conjunto de componentes TEdit e TLabel para os campos gerais do email, e um TMemo para o processo de escrita da mensagem. Na Figura 2 podemos verificar a tela que se abre do programa cliente de e-mail configurado no sistema, neste caso o Outlook Express.
Figura 1: Tela da aplicação de exemplo de envio de email utilizando ShellExecute
Figura 2: O diálogo que se abre do cliente de email, após a execução do ShellExecute
Veja o código para realizar este envio na Listagem 1:
Listagem 1: Código para realizar o envoi de e-mails utilizando ShellExecute
procedure TFormPrincipal.BtnEnviaEMailClick(Sender: TObject);
var
StringShellExecute: String;
begin
StringShellExecute := StringShellExecute +
'mailto:' +
edtPara.Text +
'?cc=' + edtCC.Text +
'&cco=' + edtCCO.Text +
'&subject=' + edtAssunto.Text +
'&body=' + memoMensagem.Lines.Text;
ShellExecute(Self.Handle, 'open',PChar(StringShellExecute),'','',SW_SHOWNORMAL);
end;
Problemas que encontramos utilizando esta solução:
1. Não é permitido o envio de anexos com esta solução
2. As quebras de linha não são respeitadas. No exemplo foi colocado um código para inclusive impedir que o usuário digite a tecla Enter (caractere ASCII #13).
Mudando a tecnologia para MAPI
Uma boa notícia para se fazer uso da tecnologia MAPI é que alguém já passou por ali e já montou um componente para facilitar o nosso trabalho! E melhor ainda saber que este alguém é o IndyProject, que tem o apoio da Nevrona (RaveReports) e da Atozed (Intraweb e FinalBuilder).
Veremos neste exemplo como configurar o componente IdMessage, disponível na paleta de componentes “Indy Misc”. Este componente nos permite configurar um e-mail completo, seja para envio com texto ou HTML. No exemplo iremos fazer o envio utilizando somente texto. Com o uso do IdMessage não teremos mais problemas para quebrar linha nem teremos problemas para realizar envio de mensagens com anexos.
Veja na Figura 3 como fica a nossa nova interface do novo exemplo. Adicionei um componente TListBox para indicar os anexos.
Figura 3: Tela utilizando o componente IdMessage para configuração da mensagem MAPI
Aproveitando um pouco o uso da Orientação a Objetos, criei uma classe para simplificar o processo de configuração do envio de e-mail e facilitar uma futura troca de componente. Estamos com isto minimizando acoplamento. Esta classe criada se chama TMailDTO e implementa os parâmetros necessários para se realizar o envio de mensagens. Veja na Listagem 2 a declaração desta classe:
Listagem 2: Código fonte da classe TMailDTO.
TMailDTO = class(TPersistent)
private
FSubject: String;
FToRecipients: TStringList;
FCCRecipients: TStringList;
FAttachments: TStringList;
FCCoRecipients: TStringList;
FBody: TStringList;
FCharSet: String;
FHighPriority: boolean;
FContentType: String;
FReplyTo: TStringList;
FTempFile: String;
procedure SetTempFile(const Value: String);
procedure SetCharSet(const Value: String);
procedure SetContentType(const Value: String);
procedure SetHighPriority(const Value: boolean);
procedure SetSubject(const Value: String);
public
property Subject : String read FSubject write SetSubject;
property ToRecipients: TStringList read FToRecipients;
property CCRecipients: TStringList read FCCRecipients;
property CCoRecipients: TStringList read FCCoRecipients;
property Body: TStringList read FBody;
property ContentType: String read FContentType write SetContentType;
property ReplyTo: TStringList read FReplyTo;
property HighPriority: boolean read FHighPriority write SetHighPriority;
property CharSet: String read FCharSet write SetCharSet;
property Attachments : TStringList read FAttachments;
property TempFile : String read FTempFile write SetTempFile;
constructor Create;
end;
Para facilitar o uso desta classe, criei um TDataModule e nele tenho uma função que realiza o envio de mensagens. Os parâmetros são recebidos em forma de TStringLists, que facilitam a interação com a interface do usuário. Estes parâmetros são adaptados e configurados no componente IdMessage. Com isto se cria uma abstração, facilitando o uso da função para envio usando MAPI. Veja na listagem 3 o código da função criada no DataModule. Neste DataModule é onde colocamos um componente do tipo TIdMessage. Veja o visual do DataModule na Figura 4:
Figura 4: Visual do DataModule com o componente IdMessage
Listagem 3: Classe de controle para envio de mensagem utilizando MAPI
Interface
...
TDMMAPIMail = class(TDataModule)
IdMessage: TIdMessage;
private
procedure AddToAddressList(AnAddressList: TIDEMailAddressList;
AStringList: TStringList);
procedure AddToAttachmentList(AMessageParts: TIdMessageParts;
AStringList: TStringList);
public
procedure SendMail(AMailDTO: TMailDTO);
end;
...
Implementation
...
procedure TDMMAPIMail.AddToAddressList(AnAddressList: TIDEMailAddressList;
AStringList: TStringList);
var
tempStr: String;
addressItem: TIdEMailAddressItem;
begin
for tempStr in AStringList do
begin
if(Trim(tempStr) <> '') then
begin
addressItem := AnAddressList.Add;
addressItem.Address := tempStr;
addressItem.Name := tempStr;
end;
end;
end;
procedure TDMMAPIMail.AddToAttachmentList(AMessageParts: TIdMessageParts;
AStringList: TStringList);
var
attach: TIdAttachment;
tempStr: String;
begin
for tempStr in AStringList do
begin
if(Trim(tempStr) <> '') then
begin
attach := TIdAttachment.Create(AMessageParts);
attach.FileName := ExtractFileName(tempStr);
attach.StoredPathName := tempStr;
end;
end;
end;
procedure TDMMAPIMail.SendMail(AMailDTO: TMailDTO);
begin
IdMessage.Subject := AMailDTO.Subject;
IdMessage.CharSet := AMailDTO.CharSet;
IdMessage.ContentType := AMailDTO.ContentType;
IdMessage.Body.Text := AMailDTO.Body.Text;
IdMessage.Headers.Add('X-Unsent: 1');
AddToAddressList(IdMessage.Recipients,AMailDTO.ToRecipients);
AddToAddressList(IdMessage.CCList,AMailDTO.CCRecipients);
AddToAddressList(IdMessage.BccList,AMailDTO.CCoRecipients);
AddToAddressList(IdMessage.ReplyTo,AMailDTO.ReplyTo);
AddToAttachmentList(IdMessage.MessageParts,AMailDTO.Attachments);
IdMessage.SaveToFile(AMailDTO.TempFile);
ShellExecute(0, 'open', PChar(AMailDTO.TempFile), '','', SW_SHOWNORMAL);
end;
Uma questão importante nesta chamada para SendMail é a adição do Header “X-Unsent”, para indicar que a mensagem é nova e ainda não foi enviada! Sem isto a mensagem é aberta como se tivesse sido uma mensagem recebida!
Para finalizar, configurado o componente IdMessage o trabalho agora é gravar a mensagem em disco e fazer o arquivo ser aberto pelo cliente de email.
No teste estamos salvando o arquivo com a extensão eml que é a extensão que o Outlook Express salva as mensagens em disco. Feito isto “executamos” o mesmo usando a função ShellExecute (unit ShellAPI).
Conclusões
E chegamos ao final de mais uma dica. Agora não tem desculpa, você pode e deve agregar a funcionalidade de envio de emails na sua aplicação. Se você não precisa anexar arquivos, o simples uso do ShellExecute pode lhe dar uma boa produtividade no uso dos emails.
E precisando de um processo mais complexo, pode fazer uso do component IdMessage ou utilizar este DataModule disponível no exemplo para download!
Links
http://www.outlookcode.com/d/mapi.htm
Uso de MAPI no Outlook/Exchange
http://www.indyproject.org/
Página do projeto dos componentes Indy
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/exchanchor/htms/msexchsvr_mapi.asp
Página no MSDN sobre MAPI e Exchange
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo