Fórum Tratamento de erros no envio de email #334091
02/12/2006
0
Estou fazendo uma aplicação que, dentre outras características, envia emails usando o Indy 9.0.19 no Deliphi 7.
Consigo enviar alguns emails sem problemas, só que, quando algo anormal acontece, a aplicação pára e me mostra uma janela de erro. Alguns exemplos de mensagens são:
-------------------------------------------------
Quando diversos emails são enviados:
´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´socom3.uol.com.br Error: too many connections from 201.44.201.83
Email não existente:
´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´<rwaller12345@uol.com.br>: Recipient address rejected: User unknown in relay recipient table
Dominio não existente:
´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´<rwaller@uol12345.com.br>: Recipient address rejected: Domain not found
-------------------------------------------------
Gostaria que esta janela não fosse mostrada, e sim me informar, de preferência com o erro, para que o usuário possa corrigí-lo.
Também gostaria de entender o que significa a primeira mensagem de erro e como evitá-la (too many connections from 201.44.201.83). Aqui uso Vírtua e pop3/smtp da Uol.
A função que estou utilizando é:
-------------------------------------------------
function TfrmEnviaEmail.Envia(Sender:TObject; Para:String):Boolean;
var
Mensagem: TIdMessage;
begin
Mensagem := TIdMessage.Create(Self);
if (Para <> ´´) then begin
idPOP31.UserName:=idSMTP1.UserName;
idPOP31.Password:=idSMTP1.Password;
// Define os parâmetros da mensagem
Mensagem.ContentType := ´text´;
Mensagem.Recipients.Add.Address := Para;
Mensagem.From.Text := ´rwaller@uol.com.br´ ;
Mensagem.Subject := ´[Teste] Envio pela aplicação´;
Mensagem.Body.AddStrings(mMensagem.Lines);
Mensagem.Headers.Values[´X-Library´] := ´´;
// Faz a conexão com o servidor e envia a mensagem
if not (IdSMTP1.Connected) then IdSMTP1.Connect();
idPOP31.Connect;
Envia:=False;
Try
IdSMTP1.Send(Mensagem);
Except
End;
if IdSMTP1.Connected then Begin
Envia:=True;
IdSMTP1.Disconnect;
End;
if IdPOP31.Connected then
IdPOP31.Disconnect;
End;
Mensagem.Free;
end;
-------------------------------------------------
Creio que já pesquisei os todos os tópicos deste fórum sobre este assunto. Inclusive foi por isso que instalei a última versão do Indy. Quanto à conectar no Pop antes do Smtp (dica de outro tópico), creio que não vi diferença.
Gostaria MUITO que pudéssem me ajudar, se for possível.
Obrigado :)
Abraços,
Rudolf
Rudolf Waller
Curtir tópico
+ 0Posts
02/12/2006
Massuda
´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´<rwaller@uol12345.com.br>: Recipient address rejected: Domain not found[/quote:6231382b7d]Esse tipo de exceção deveria ser capturado num try..except e ser tratada adequadamente.
[quote:6231382b7d=´Rudolf Waller´]Gostaria que esta janela não fosse mostrada, e sim me informar, de preferência com o erro, para que o usuário possa corrigí-lo.[/quote:6231382b7d]Pelo código que você postou, essa janela só está aparecendo porque você está executando o programa de dentro da IDE do Delphi. se executar o programa a partir do Windows, provavelmente nada será exibido. Isso porque você pos um try..except ao redor do Send que está feito para engulir silenciosamente toda exceção. Quando você implementar o tratamento da exceção, note que a exceção possui uma propriedade ReplyErrorCode, que é um Integer, mais fácil de tratar que a string contida na propriedade Message da exceção.
[quote:6231382b7d=´Rudolf Waller´]´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´socom3.uol.com.br Error: too many connections from 201.44.201.83[/quote:6231382b7d]Esse erro é estranho. Pelo seu código, isso só ocorreria se você estiver executando o envio de email dentro de um loop. É o caso?
Eu prefiro esta versão do seu código...
function TfrmEnviaEmail.Envia(Sender:TObject; Para:String):Boolean; var Mensagem: TIdMessage; begin if (Para <> ´´) then begin Mensagem := TIdMessage.Create(nil); try // Define os parâmetros da mensagem Mensagem.ContentType := ´text´; Mensagem.Recipients.Add.Address := Para; Mensagem.From.Text := ´rwaller@uol.com.br´ ; Mensagem.Subject := ´[Teste] Envio pela aplicação´; Mensagem.Body.AddStrings(mMensagem.Lines); Mensagem.Headers.Values[´X-Library´] := ´´; idPOP31.UserName:=idSMTP1.UserName; idPOP31.Password:=idSMTP1.Password; idPOP31.Connect; try IdSMTP1.Connect; Envia:=False; Try IdSMTP1.Send(Mensagem); Envia:=True; Except on e: EIdProtocolException do begin // trata a exceção end; End; IdSMTP1.Disconnect; finally IdPOP31.Disconnect; end; finally Mensagem.Free; end; End; end;
[quote:6231382b7d=´Rudolf Waller´]Quanto à conectar no Pop antes do Smtp (dica de outro tópico), creio que não vi diferença.[/quote:6231382b7d]Muitos provedores de acesso exigem isso para poder usar o servidor SMTP.
Gostei + 0
03/12/2006
Rudolf Waller
Antes de mais nada, obrigado pela força :)
Sim, estou dentro da IDE. Posso estar enganado (não conheço muito Delphi), mas me parece que, mesmo mostrando a janela via raise, o programa não entra no except. É assim mesmo? Tem como sempre entrar (supondo que haja uma exceção), mesmo estando na IDE?
Relendo o que você escreveu e tentando entender o help do try...except, acho que não coloquei a exceção certa. Por isso não interpretou o que coloquei no except anteriormente. Vou checar isso melhor...
Vou fazer um teste agora mesmo
Interessante! Gostei :)
Na sugestão que você postou, esta propriedade seria e.ReplyErrorCode?
Existem diversas exceções no Indy. Eu teria que fazer uma análise como:
on e: EIdProtocolException do ... // Da sua sugestão
on e: EIdProtocolReplyError do ... // Uma das exceções
e assim por diante? Ou tem como, a partir do valor de uma única propriedade, fazer esta análise?
[/quote:6c204789a1]
Sim, é o caso. Pelo que entendi da sua resposta, posso tratar esta exceção e re-enviar o email.
Vou fazer um teste agora mesmo :)
Massuda, já trabalhei muito com o Turbo Pascal, mas conheço muito pouco de Delphi. Ontem preferi copiar o Indy para outra pasta para poder alterá-lo, ao invés do original. Feito isso, passei a tentar entender o que faz e alterá-lo para que não gere uma exceção. Aparentemente está funcionando bem, apesar de não ter certeza que as alterações que fiz estão 100¬ confiáveis. Como costuma dizer um amigo: ´Não é porque funciona que está certo´ :)
Isso foi bom que me permitiu entender um pouco de como funciona o SMTP. Acho que estou preferindo seguir o seu conselho e usar o código original, feito por profissionais que entendem do assunto, e que está mais do que debugado, ao contrário do que fiz.
De qualquer maneira, aquela função ficou assim:
function TfrmEnviaEmail.Envia(Sender:TObject; Para:String):Boolean; var Mensagem: TIdMessage; I:Integer; x:string; begin Mensagem := TIdMessage.Create(Self); if (Para <> ´´) then begin // Define os parâmetros da mensagem Mensagem.ContentType := ´text´; Mensagem.Recipients.Add.Address := Para; Mensagem.From.Text := ´rwaller@uol.com.br´ ; Mensagem.Subject := ´[Teste]´; Mensagem.Body.AddStrings(mMensagem.Lines); Mensagem.Headers.Values[´X-Library´] := ´´; // Faz a conexão com o servidor e envia a mensagem Repeat IdSMTP1.Connect(1000); If not (IdSMTP1.Connected) Then Begin lblNumErros.Caption:=IntToStr(StrToInt(lblNumErros.Caption)+1); Application.ProcessMessages; End; Until IdSMTP1.Connected Or Cancela; If Cancela Then Begin Result:=False; Exit; End; IdSMTP1.Send(Mensagem); if IdSMTP1.Connected then IdSMTP1.Disconnect; Res:=idSMTP1.LastCmdResult.Text.Text; Num:=idSMTP1.LastCmdResult.NumericCode; End; Mensagem.Free; Result:=Copy(Res,1,2)=´Ok´; end;
Nenhuma exceção nesta manga, nem na outra também :) Só não posso garantir que todas as alterações que fiz estão certas.
Com certeza :)
Massuda, novamente, obrigado pela força :)
Abraços,
Rudolf
Gostei + 0
03/12/2006
Rudolf Waller
Acabei de testar a sua sugestão com o Indy original.
Vamos aos resultados:
Confere! A janela só aparece dentro da IDE. Tem como não aparecer lá dentro, mesmo que seja numa etapa de teste? Ficaria mais próximo da aplicação final.
[quote:11888344ed=´Rudolf Waller´]Sim, estou dentro da IDE. Posso estar enganado (não conheço muito Delphi), mas me parece que, mesmo mostrando a janela via raise, o programa não entra no except. É assim mesmo? Tem como sempre entrar (supondo que haja uma exceção), mesmo estando na IDE?
[/quote:11888344ed]
A exceção estava errada. Me baseei no que você postou e já corrigi. Ficou uma dúvida: Tive que colocar na unha a unit idException na cláusula Uses, pois senão o Delphi não acharia as exceções do Indy.
É assim mesmo? Quero dizer, tenho que localizar qual unit tem as exceções (supondo que eu tenha o fonte do componente) e digitar o nome desta unit? E se eu não tiver o fonte? Ou estou fazendo o caminho mais difícil? (novamente, (ainda) sou leigo em Delphi)
Corrigido
Confere! Gostei deste rapaz! Cada dia que passa mais me admiro com o Delphi :)
Criei diversas exceções, inclusive analisando o ReplyErrorCode. Valeu!
Vou fazer um teste agora mesmo :)
[/quote:11888344ed]
Funfando joinha. Agora vamos aos detalhes :)
Massuda, novamente, obrigado pela força :)
Abraços,
Rudolf
Gostei + 0
03/12/2006
Massuda
[quote:6a4da650c8=´Rudolf Waller´]Tive que colocar na unha a unit idException na cláusula Uses, pois senão o Delphi não acharia as exceções do Indy. É assim mesmo?[/quote:6a4da650c8]Sim. O Delphi inclui automaticamente apenas o mínimo de units necessárias para cada componente que você põe num form/data module; qualquer outra unit que você precise você tem que incluir manualmente.
Gostei + 0
03/12/2006
Rudolf Waller
Feito
Massuda, a aplicação tá rodando belezinha, mas fiquei com uma pulga atrás da orelha: Ontem escondi as exceções do Indy e hoje as estou tratando. Ontem estava enviando mais de um email por segundo (média), hoje está demorando alguns segundos. Perguntinha bem genérica: o que pode estar acontecendo? Faz sentido isso?
Abraços,
Rudolf
Gostei + 0
04/12/2006
Massuda
Gostei + 0
04/12/2006
Rudolf Waller
Grande Massuda,
Tentei enviar 10 emails por conexão, e não fez quase diferença. Coloquei um Tmemo para mostrar os enventos de status do idSMTP. A aplicação demora muito em ´encoding text´, praticamente os 5s do envio estão aqui.
Tem alguma coisa que posso fazer para otimizar isso? Como informação extra, o email tem uns 12Kb em modo texto (não é HTML).
Valeu novamente :)
Abraços,
Rudolf
Gostei + 0
06/12/2006
Rudolf Waller
Achei o erro, e já está corrigido!
Valeu pela força :)
Abraços,
Rudolf
Gostei + 0
06/12/2006
Massuda
Gostei + 0
08/12/2006
Rudolf Waller
Grande Massuda,
Na versão original, criei o TIdMessage cada vez que entrava na rotina. Para facilitar, coloquei um componente idMessage no form.
Como cada vez que entrava na rotina ele anexava mais um destinatário, a lista ia aumentando cada vez mais. Num teste que fiz enviando para meu próprio email, ao invés de receber 100 emails recebi mais de 5000 :O
Nestas hora me lembro de uma frase de humor que rolava nas conversas do BBS: ´Definitivamente este era o último bug´ :D
Abraços,
Rudolf
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)