Buscar

Windows Service e envio de Email por SMTP

Código

Delphi: D7
SO: Windows XP Pro 32Bits
Nível: Básico - Intermediário
Descrição: Criação de um Windows Service com a finalidade de envio de arquivos de texto por e-mail utilizando o protocolo de envio SMTP.
Componentes: TTimer, TidSMTP e TidMessage.
Requisitos: Conta de e-mail com possibilidade de configuração de servidor SMTP(Ex: smtp.uol.com.br) e o básico em lógica.

Criando e Configurando o Serviço -

1- File -> New -> Other -> Service Application.
Repare que a estrutura é semelhante à criação de uma aplicação comum, entretanto, é criado um pequeno modulo em branco semelhante ao DataModule, onde você irá adicionar os componentes necessários.

Recomendo que você crie um pasta para o seu Serviço.

Windows Services rodam no background e por essa razão são ótimas opções para verificar atualizações, envio de relatório, manutenção de sistemas, acessar WebServices sem ter de interromper qualquer outra operação para que a mesmo ocorra(A Web, FTP, or e-mail server is an example of a service application. Fonte: Help do Delphi). A desvantagem é que Windows Services não suportam componentes visuais e não são muito flexíveis. Mas é possível adicionar um form por exemplo e roda-lo junto com o serviço.

Vá em Iniciar -> Executar... e digite: services.msc e dê [Enter], você poderá visualizar todos o serviços instalados em seu computador. Pelo Gerenciador de tarefas do Windows(Ctrl+Alt+Del) você poderá ver aqueles que estão sendo executados.

Após a criação do Service Application, clique no Object TreeView, sobre "Service1" que é o nome dado por padrão pelo Delphi, e logo abaixo veja algumas das propriedades do mesmo:

a) Allow Pause: Permitir pausar o serviço? Deixe como False. Deixando em False não precisaremos cuidar dos Eventos OnPause e OnContinue posteriormente.

b) Allow Stop: Permitir parar o serviço? Deixe em True, assim podemos parar o serviço pelo service.msc, ou Dos, e não teremos problemas em desinstalar o serviço depois. Não precisaremos tratar o evento OnStop pois utilizaremos apenas uma Thread no serviço, a própria de sua execução.

c) Dependencies: Propriedade que permite utilizar outros serviços junto ao nosso, isto é, nosso serviço depende de outro(s) para funcionar corretamente. Não usaremos. Um exemplo ocorre quando queremos efetuar um backup periódico de um DB e precisamos que um serviço esteja sendo executado para tal. Para adicionar outro(s) serviço vá em File -> New -> Other -> Service.

d) DisplayName: O nome do serviço. Coloque SSendLog1. Este nome é o que aparecerá no services.msc, e será utlizado para iniciar e parar o serviço. O nome que aparecerá no Gerenciador de tarefas do Windows será o nome do projeto, sendo assim o nome do executável final, que será utilizado para instalar e desinstalar o serviço.

e) Interactive: Sete como True. Esta propriedade é responsável pela interação entre o serviço e componentes visuais. Deixamos true pois utilizaremos API e os testes que fiz em True e False, o e-mail é enviado mais facilmente em True.

f) Password e ServiceStartName: Utilizado no caso do serviço necessitar de permissão administativa.

O restante deixe como está por padrão.

Salve o projeto neste momento, dê o nome de SSendLog1 ao projeto.

Quanto aos eventos não vou explicar pois são auto-explicativos. Veja por sí na aba Events.

Configurando Componentes Adicionais -

2- Adicione um componente Timer, um idSMTP e um idMessage (Paletas System, IndyClients e IndyMisc respectivamente).

3- Clique sobre o TTimer vá até a propriedade Enabled e sete como False e Interval em 30000(30 segundos, você pode alterar se preferir).

4- Clique sobre o componente TidSMTP, vá até a propriedade Host e digite o servidor SMTP de envio(Ex: smtp.uol.com.br), Password a sua senha de acesso ao e-mail, Port a porta para conexão com o servidor e Username o seu login.

5- Clique no TidMessage, propriedades, From, em Adress o seu e-mail e em Name seu nome.

Salve seu projeto neste momento.

Codificando -

6- Declare uma constante tipificada do tipo String e duas variáveis globais uma do tipo Integer e outra String, como segue:
Código:

Const
{$J+}
 NomeArquivoTmp : String = 'Log';
{$J-}

var
  Service1: TService1;
  Count : Integer;
  ArquivoAnexo : String;

NomeArquivoTmp e Count serão utilizados para dar nome ao arquivo de texto através de uma função.
ArquivoAnexo é utilizado na criação do anexo.

7- Vamos adicionar três funções ao nosso serviço na seção Implementation, a primeira:
Código:

Function DiaHora : String;
Begin
 DateSeparator := '-';
 TimeSeparator := '-';
 Result := DateTimeToStr(NOW);
End;

Ela nos retorna o dia e hora. Será utilizada para formatar o nome do arquivo e dar algum conteúdo ao mesmo. Você pode formatar melhor essa função depois.

Para a segunda função, adicione a Wininet em Uses e o código a seguir:
Código:

Function EstaConectado : Bool;
Begin
 If InternetCheckConnection('http://www.google.com/',1, 0) then
  Result := True
 Else
  Result := False;
End;

Com está função verificamos, através da API se o computador encontra-se conectado na internet. Para mais informações pressione Ctrl e clique sobre o nome Wininet.

A função InternetCheckConnection tenta estabelecer conexão com o site da Google. (Allows an application to check if a connection to the Internet can be established. Fonte: msdn).

Wininet é uma DLL disponível desde o Internet Explorer 4 que possui diversas funções relativas a FTP, modem, etc. (Informações-msdn)

A terceira função será a responsável por salvar o arquivo:
Código:

{$O+}
Function Salva(Dado : String) : Bool;
Var
 Arquivo : TStringList;
Begin
If EstaConectado Then
Begin
Result := True;
 Try
  Count := Count + 1;
  NomeArquivoTmp := NomeArquivoTmp + IntToStr(Count) + ' ' + DiaHora + '.txt';
  Arquivo := TStringList.Create;
   Try
    Arquivo.Add(Dado);
    Arquivo.SaveToFile('C:' + NomeArquivoTmp);
   Finally
    Arquivo.Free;
   End;
 Finally
  ArquivoAnexo := NomeArquivoTmp;
  NomeArquivoTmp := 'Log';
 End
End
Else
 Begin
  Result := False;
  Exit;
 End;
End;
{$O-}

Primeiro declarei a diretiva de compilação {$0+} que serve para otimizar a compilação neste ponto do código. Ao fim declara-se {$0-}. Fiz testes onde houve uma pequena melhora na execução do serviço.

Pois bem, testo primeiramente se há conectividade, caso contrário não salva o arquivo. Inicio contador(Count), Formato o nome do arquivo(NomeArquivoTmp), e inicio a variável do tipo TStringList, adiciono algum conteúdo(Dado), e salvo o arquivo. Depois, declaro qual será o anexo do e-mail e "reseto" a constante tipificada.

8- Dê um duplo clique sobre o TTimer para que ele vá até o evento OnTimer, e adicione o seguinte código para que fique dessa forma em sua totalidade:
Código:

{$O+}
procedure TService1.Timer1Timer(Sender: TObject);
Begin
If Salva(DiaHora) = True Then
Begin
 Try
  idMessage1.Recipients.EMailAddresses := 'julio@arquivojuridico.com';
  idMessage1.Subject := DiaHora;
  idMessage1.Body.Text := 'Arquivo de log do dia: ' + DiaHora;
  TidAttachment.Create(idMessage1.MessageParts, TFileName('C:' + ArquivoAnexo));
  idSMTP1.Connect;
  If idSMTP1.Connected = True Then
   Begin
    Try
     idSMTP1.Send(idMessage1);
    Finally
     idSMTP1.Disconnect;
     idMessage1.MessageParts.Clear;
     DeleteFile('C:' + ArquivoAnexo);
    End;
   End;
 Except
  On E : Exception Do
   Exit;
 End;
End
Else
 Exit;
End;
{$O-}

Primeiro verifico se foi possível salvar o arquivo com o Dado que eu especifiquei, se sim, é por que há conectividade, caso contrário não faz nada.
Depois, começo a configurar o IdMessage, com o e-mail de destino, assunto, mensagem e configuro o anexo.
Mando conectar e verifico se foi estabelecida a conexão, se sim, mando enviar. Em seguida, desconecto, limpo o anexo e deleto o arquivo.

9- Clique no Object TreeView, sobre "Service1" e vá até a propriedade AfterInstall, adicione o código:
Código:

Begin
Count := 0;
WinExec('command.com /c net start SSendLog1', SW_HIDE);
end;

Definimos o contador(Count) para iniciar em "0" e dizemos ao serviço que após ser instalado inicie.

10- Clique no Object TreeView, sobre "Service1" e vá até a propriedade OnExecute, adicione o código:
Código:

begin
Timer1.Enabled := True;
While Not Self.Terminated do
ServiceThread.ProcessRequests(True);
Timer1.Enabled := False;
end;

Habilitamos o TTimer.
Windows Service funciona na base de Threads, no caso como só temos uma, a própria do serviço, devemos dizer que enquanto não terminou a execução do serviço queremos que chame a Thread. Se não fizermos isso o serviço não terá funcionalidade, pois não conseguirá executar nada.
E por fim, se por algum motivo o serviço não for executado, desabilitamos o TTimer por segurança.

Salve o projeto. Dê Ctrl + F9 para compilar. Se você tentar executa-lo não acontecerá nada.

Instalação e Desinstalação -

11- Vá em Iniciar -> Executar... e digite: "C:Localização do seu serviçoSSendLog1.exe" /install

Irá aparecer uma mensagem que o serviço foi instalado com sucesso. Aguarde o tempo que você colocou no TTimer e verifique sua caixa de entrada.

12- Para desinstalar primeiro pare o serviço. Acesse o Executar no menu Iniciar, digite cmd e dê [ENTER].
Digite: net stop SSendLog1 e aguarde.

13- Para desinstalar Vá em Iniciar -> Executar... e digite: "C:Localização do seu serviçoSSendLog1.exe" /uninstall

Aguarde e aparecerá um mensagem dizendo que o serviço foi desinstalado.

Como opcional, tanto para instalar e desinstalar pode-se utilizar /silent no fim da linha de comando para que não seja mostrada nenhuma informação.

Qualquer dúvida estamos aqui.

Referências:
http://msdn.microsoft.com/en-us/library/aa384346(VS.85).aspx
http://msdn.microsoft.com/pt-br/library/3w2azyt6.aspx

Abraço,
Júlio César Schincariol Filho

Publicidade

Vote na dica




Quantidade de votos: 0 votos
Aceitação: 0%


Detalhes da dica

Categoria: Windows
Adicionada dia: 31/07/10
Por: Júlio César Schincariol Filho
Visualizada: 13907 vezes

Planeta Delphi - Tudo sobre programação Delphi Planeta Delphi - www.planetadelphi.com.br - Todos os direitos reservados | Copyright 2001-2009