无法使用Indy发送电子邮件,冻结程序

时间:2014-05-20 07:45:35

标签: delphi delphi-2010 email-attachments indy

当我尝试使用indy发送带附件的电子邮件时,我的程序冻结,我不知道为什么。 这是我用于发送电子邮件的表单的完整代码。

unit Dok_sutisana;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdMessage, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase,
IdSMTP, StdCtrls, Buttons, ComCtrls, IdAttachmentFile;

type
TForm14 = class(TForm)
  Edit1: TEdit;
  Edit2: TEdit;
  Label1: TLabel;
  Label2: TLabel;
  BitBtn1: TBitBtn;
FontDialog1: TFontDialog;
RichEdit1: TRichEdit;
IdSMTP1: TIdSMTP;
IdMessage1: TIdMessage;
BitBtn2: TBitBtn;
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
 end;

var
 Form14: TForm14;

 implementation

 uses Autentif, EDGA;

{$R *.dfm}

procedure TForm14.BitBtn1Click(Sender: TObject);
begin
if FontDialog1.Execute() then
RichEdit1.Font:=FontDialog1.Font;
end;

procedure TForm14.BitBtn2Click(Sender: TObject);
var s:string;
begin
form3.ADOTable1.Active:=true;
//setup SMTP
IdSMTP1.Host := form3.adotable1['smtp'];
IdSMTP1.Port := form3.adotable1['ports'];
IdSMTP1.Username:= '******@gmail.com';
IdSMTP1.Password:='******';

//setup mail message
IdMessage1.From.Address := form3.adotable1['e-pasts'];
IdMessage1.From.Name:= form3.adotable1['Vards']+' '+ form3.adotable1['Uzvards'];
IdMessage1.Recipients.EMailAddresses := edit1.Text;;

IdMessage1.Subject := edit2.Text;
IdMessage1.Body.Add(RichEdit1.Text + form3.ADOTable1['paraksts']);
s:= GetCurrentDir + form1.ADOTable1['Dok_adr'];
TIdAttachmentFile.Create(IdMessage1.MessageParts, s ) ;

//send mail

IdSMTP1.Connect() ;
IdSMTP1.Send(IdMessage1) ;
IdSMTP1.Disconnect;
IdMessage1.Free;
IdSMTP1.Free;

form3.ADOTable1.Active:=false;
Form14.Close;
end;

end.

我希望能够帮助解决我的问题。

2 个答案:

答案 0 :(得分:3)

Indy使用阻塞操作,并且您在主UI线程的上下文中使用Indy。因此,当TIdSMTP忙时,您的主线程将被阻止处理新消息,从而冻结应用程序的外观,直到TIdSMTP完成。

为避免冻结,您可以:

  1. (首选解决方案)将TIdSMTP代码移到单独的工作线程中。

  2. TIdAntiFreeze个组件放到您的表单上。这将允许主消息队列继续处理新消息,而其他Indy组件在主线程中运行。

  3. 为了更好地衡量,您还应设置TIdSMTP.ConnectTimeoutTIdSMTP.ReadTimeout属性,以便Connect()Send()不会长时间阻止。如果发生超时,将引发适当的异常以中止操作。

答案 1 :(得分:0)

我从您的代码中删除了ADO的使用,并为我的电子邮件帐户使用了硬编码值(出于安全原因在此处删除了 - 您可以将占位符替换为工作帐户)。

此代码有效 - 它会发送附件。

我也是:

  • 在连接周围添加了一个try / finally,以确保在send抛出异常时释放它;
  • 添加了Lemy提到的ConnectTimeout选项;
  • 清理了电子邮件正文。在添加新内容之前(否则您最终会得到多个测试副本);
  • 需要删除之前的附件,否则您的第二封电子邮件会以第一个附件中的

    结尾
    IdSMTP1.Host := '******';
    IdSMTP1.Port := 25;
    IdSMTP1.Username:= '******@gmail.com';
    IdSMTP1.Password:='******';
    IdMessage1.From.Address := '******';
    IdMessage1.From.Name:= '******';
    IdMessage1.Recipients.EMailAddresses := '******';
    IdMessage1.Subject := '******';
    IdMessage1.Body.Clear; // Clear the email body
    IdMessage1.Body.Add('******');
    s:= GetCurrentDir + '\******';
    IdMessage1.MessageParts.Clear;
    TIdAttachmentFile.Create(IdMessage1.MessageParts, s ) ;
    
    IdSMTP1.ConnectTimeout := 2400 ;
    IdSMTP1.Connect();
    try
        IdSMTP1.Send(IdMessage1) ;
    finally
        IdSMTP1.Disconnect;
    end; 
    

正如这个简单的例子有效,你的问题可能是:

  • 表格中的电子邮件名称/密码/值不正确;
  • 防止程序访问TCP的防病毒软件包;
  • 尝试使用您的ISP未提供的电子邮件帐户

当我更换ISP时,旧版本无法正常工作(访问需要SMTPS)但是当我交换使用我的宽带供应商提供的电子邮件帐户时,这不需要SMTPS,而是使用普通SMTP,因为它在网络中因此值得信赖