Tratamento de erros no envio de email
Oi pessoal,
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
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
Curtidas 0
Respostas
Massuda
02/12/2006
[quote:6231382b7d=´Rudolf Waller´]´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´<rwaller12345@uol.com.br>: Recipient address rejected: User unknown in relay recipient table
´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...Evite ficar desnecessariamente conectado no servidores POP e SMTP.
[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.
´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
Rudolf Waller
02/12/2006
Grande Massuda,
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:
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
Antes de mais nada, obrigado pela força :)
[quote:6c204789a1=´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.
Pelo código que você postou, essa janela só está aparecendo porque você está executando o programa de dentro da IDE do Delphi.[/quote:6c204789a1]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...
se executar o programa a partir do Windows, provavelmente nada será
exibido.
Vou fazer um teste agora mesmo
Isso porque você pos um try..except ao redor do Send que está feito para engulir silenciosamente toda exceção.
Interessante! Gostei :)
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.
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=´Rudolf Waller´]´Project Agenda.exe raised exception class EIdProtocolReplyError with message ´socom3.uol.com.br Error: too many connections from 201.44.201.83
Esse erro é estranho. Pelo seu código, isso só ocorreria se você estiver executando o envio de email dentro de um loop. É o caso?[/quote:6c204789a1]
Sim, é o caso. Pelo que entendi da sua resposta, posso tratar esta exceção e re-enviar o email.
Eu prefiro esta versão do seu código...
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.
Evite ficar desnecessariamente conectado no servidores POP e SMTP.
Com certeza :)
Massuda, novamente, obrigado pela força :)
Abraços,
Rudolf
GOSTEI 0
Rudolf Waller
02/12/2006
Grande Massuda,
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
Acabei de testar a sua sugestão com o Indy original.
Vamos aos resultados:
Pelo código que você postou, essa janela só está aparecendo porque você está executando o programa de dentro da IDE do Delphi.
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)
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...
Corrigido
se executar o programa a partir do Windows, provavelmente nada será
exibido.
Confere! Gostei deste rapaz! Cada dia que passa mais me admiro com o Delphi :)
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.
Criei diversas exceções, inclusive analisando o ReplyErrorCode. Valeu!
[quote:11888344ed=´Massuda´]
Eu prefiro esta versão do seu código...
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
Massuda
02/12/2006
[quote:6a4da650c8=´Rudolf Waller´]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:6a4da650c8]Na maioria das versões do Delphi vá em [b:6a4da650c8]Tools|Debugger options[/b:6a4da650c8], selecione a aba [b:6a4da650c8]Language exceptions[/b:6a4da650c8] e desmarque a opção [b:6a4da650c8]Stop on Delphi exceptions[/b:6a4da650c8]
[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.
[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
Rudolf Waller
02/12/2006
Na maioria das versões do Delphi vá em [b:cd438dd7d9]Tools|Debugger options[/b:cd438dd7d9], selecione a aba [b:cd438dd7d9]Language exceptions[/b:cd438dd7d9] e desmarque a opção [b:cd438dd7d9]Stop on Delphi exceptions[/b:cd438dd7d9]
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
Massuda
02/12/2006
[quote:234bed95ca=´Rudolf Waller´]... Ontem estava enviando mais de um email por segundo (média), hoje está demorando alguns segundos...[/quote:234bed95ca]Você está mandando emails em um loop? Se for, mude o código para conectar com os servidores, mandar os emails e desconectar dos servidores. Os códigos postados aqui conectam/desconectam dos servidores a cada envio de mensagem.
GOSTEI 0
Rudolf Waller
02/12/2006
[quote:98841361fe=´Rudolf Waller´]... Ontem estava enviando mais de um email por segundo (média), hoje está demorando alguns segundos...
Você está mandando emails em um loop? Se for, mude o código para conectar com os servidores, mandar os emails e desconectar dos servidores. Os códigos postados aqui conectam/desconectam dos servidores a cada envio de mensagem.[/quote:98841361fe]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
Rudolf Waller
02/12/2006
Grande Massuda,
Achei o erro, e já está corrigido!
Valeu pela força :)
Abraços,
Rudolf
Achei o erro, e já está corrigido!
Valeu pela força :)
Abraços,
Rudolf
GOSTEI 0
Massuda
02/12/2006
Apenas curiosidade... se não for segredo, o que era?
GOSTEI 0
Rudolf Waller
02/12/2006
Apenas curiosidade... se não for segredo, o que era?
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