2014-05-20 45 views
3

當我嘗試發送附件使用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. 

我希望惠普,我可以得到一些幫助我的問題。

+0

你有沒有嘗試用調試器逐步通過你的代碼?可能有助於確切知道哪一步鎖定。你也需要嘗試......最後圍繞連接/斷開連接和內存創建/釋放。可能是第一次通過你連接,但不要斷開,然後你將不得不等待連接超時。 – DavidG

+0

@DavidG鎖定發生在IdSMTP TIdSMTP.Connect函數中 – sistemcrash

+0

當我使用這個庫時,我有另外一行:「IdSMTP1.NeedAuthentication:= false;」和「IdSMTP1.UseTLS:= emNOTLSSupport」。我懷疑你可以在連接之前嘗試第一行,看看會發生什麼。 – DavidG

回答

3

Indy使用阻塞操作,並且您在主UI線程的上下文中使用Indy。因此,儘管TIdSMTP處於忙碌狀態,但您的主線程將無法處理新消息,從而導致應用凍結,直到TIdSMTP完成。

爲了避免凍結,您可以:

  1. (首選的解決方案)將您的TIdSMTP代碼放到一個單獨的工作線程。

  2. 將一個TIdAntiFreeze組件拖放到您的表單上。這將允許主消息隊列繼續處理新消息,而其他Indy組件正在主線程中運行。

良好的措施,你還應該設置TIdSMTP.ConnectTimeoutTIdSMTP.ReadTimeout屬性,以便Connect()Send()沒有爲長時間阻塞。如果發生超時,則會引發相應的異常以中止操作。

+0

我添加了'TIdAntiFreeze'並試圖再次發送電子郵件。該程序仍然無法工作,但我可以按下發送按鈕並引發一個異常,即'EIdAlready connected',程序無法繼續。 – sistemcrash

+0

當「連接」爲真時調用Connect()時會引發'EIdAlreadyConnected'。請記住,如果'IOHandler.InputBuffer'中有未讀數據,即使底層套接字已關閉,「Connected」也可以爲真。因此,如果您需要在活動連接期間關閉套接字並重新連接,請確保在再次調用Connect()之前清除「InputBuffer」。 –

+0

如果發生連接,爲什麼郵件還沒有發送? – sistemcrash

0

我從您的代碼中刪除了對ADO的使用,併爲我的電子郵件帳戶使用硬編碼的值(此處因安全原因已刪除 - 您可以用佔位符替換工作帳戶)。

此代碼工作 - 它發送附件。

我也:

  • 添加一個try /終於周圍的連接,以確保如果發送拋出一個異常,它被釋放;
  • 添加了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;
  • 嘗試使用電子郵件時我改變了互聯網服務供應商,舊的沒有工作(訪問需要SMTPS),但是當我換用我的寬帶供應商提供的電子郵件帳戶,帳戶,而不是你的ISP

提供,這不需要SMTPS,但工作在普通的SMTP,因爲它是在他們的網絡,因此信任

+1

雖然它是不錯,你經歷了所有這些努力,但它並沒有回答這個問題。正確的答案是Indy被阻塞,所以你的代碼會停止,直到對'IdSMTP1.Send'的調用返回。雷米的回答有正確的信息,這是一個單獨的線程或使用'TIdAntiFreeze'(按照首選順序)阻止主線程(UI)線程。 (海報的代碼也會發送附件;問題是如何防止它在用戶界面凍結時凍結)。 –