0

GMail 経由で Indy を使用して添付ファイル付きのメールを送信することについて以前に質問しましたが、基本的なコードが適切に機能することを嬉しく思います。ただし、添付ファイルの送信には数分かかり、その間にプログラムがフリーズすることに気付きました (プログラムに TIdAntiFreeze コンポーネントを追加したにもかかわらず)。電子メールを別のスレッドで送信して、プログラムが応答できるようにすることをお勧めします。

スレッドから電子メールを送信する方法を示すコードをウェブ上で見つけることができなかったため、部分的にしか機能しない独自のコードを作成する必要がありました。

電子メールを送信するフォームから SMTP コンポーネントを削除しました。代わりに、電子メール コンポーネントのデータを (TIdMessage.SaveToFile メソッドを使用して) ディスクに保存してから、非モーダル ダイアログを作成します。これにより、必要なコンポーネントをインスタンス化して電子メールを送信するスレッドが作成されます。SMTP および IdMessage コンポーネントのイベント ハンドラーを作成したいのですが、実行時にこれを行う方法がわかりません。スレッド コードはフォーム メソッドにアクセスできません。

私は自分のコードを示していますが、適切に動作するものを見たいと思っています。

unit Manage77c;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, SizeGrip, ManageForms, ExtCtrls, StdCtrls, IdBaseComponent,
 IdComponent, IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase,
 IdMessageClient, IdSMTPBase, IdSMTP, IdIOHandler, IdIOHandlerSocket, IdSSL,
 IdIOHandlerStack, IdMessage, IdSSLOpenSSL;

type
 TSendAMail = class(TForm)
 mem: TMemo;
 procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
public
 constructor create (const s: string);
end;

implementation

{$R *.dfm}

var
 ahost, apassword, ausername, curstatus, fn: string;
 caller: thandle;

function DoEmail (p: pointer): longint; stdcall;
var
 ssl: TIdSSLIOHandlerSocketOpenSSL;
 email: TIdMessage;

begin
 caller:= THandle (p);
 email:= TIdMessage.create;
 with email do
  begin
   loadfromfile (fn);
   // OnInitializeISO:= ??
  end;

 deletefile (fn); 
 ssl:= TIdSSLIOHandlerSocketOpenSSL.create;
 ssl.SSLOptions.SSLVersions:= [sslvTLSv1];

 with TIdSMTP.create do  
  try
   //OnStatus:= ??
   iohandler:= ssl;
   host:= ahost;
   password:= apassword;
   username:= ausername;
   port:= 587;
   useTLS:= utUseExplicitTLS;
   Connect;
   try
    Send (email);
   except
    on E:Exception do;
   end;
  finally
   Disconnect;
   free
  end;
 ssl.free;
 email.free;
 result:= 0
end;

constructor TSendAMail.Create (const s: string);
var
 empty: boolean;
 thrid: dword;

begin
 inherited create (nil);
 fn:= s;
 repeat
  with dm.qGetSMTP do  // this part gets the SMTP definitions from the database
   begin
    open;
    aHost:= fieldbyname ('smtphost').asstring;
    ausername:= fieldbyname ('smtpuser').asstring;
    apassword:= fieldbyname ('smtppass').asstring;
    close
   end;

  empty:= (ahost = '') or (ausername = '') or (apassword = '');
  if empty then
   with TGetSMTP.create (nil) do   // manage77a
    try
     execute
    finally
     free
    end;
 until not empty;
 CreateThread (nil, 0, @DoEmail, pointer (self.handle), 0, thrid);
 close
end;

procedure TSendAMail.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 action:= caFree
end;

end.
4

1 に答える 1

2

TThread関数の代わりにクラスを使用CreateThread()すると、クラスのメソッドをイベント ハンドラーとして使用できます。

unit Manage77c;

interface

procedure SendAMail (const AFileName: string);

implementation

uses
 SysUtils, Classes, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
 IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase, IdSMTP, IdIOHandler,
 IdIOHandlerSocket, IdSSL, IdIOHandlerStack, IdMessage, IdSSLOpenSSL;

type
  TEmailThread = class(TThread)
  private
    FFileName: string;
    FHost: string;
    FPassword: string;
    FUsername: string;
    ...
    procedure DoInitializeISO(var VHeaderEncoding: Char; var VCharSet: string);
    procedure DoStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
    ...
  protected
    procedure Execute; override;
  public
    constructor Create(const AFileName, AHost, APassword, AUsername: string); reintroduce;
  end;

constructor TEmailThread.Create(const AFileName, AHost, APassword, AUsername: string);
begin
  inherited Create(False);
  FreeOnTerminate := True;
  FFileName := AFileName;
  FHost := AHost;
  FPassword := APassword;
  FUsername := AUsername;
  ...
end;

procedure TEmailThread.Execute;
var
  smtp: TIdSMTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  email: TIdMessage;
begin
  email := TIdMessage.Create(nil);
  try
    email.LoadFromFile(FFileName);
    email.OnInitializeISO := DoInitializeISO;

    DeleteFile (FFileName); 

    smtp := TIdSMTP.Create(nil);
    try
      ssl := TIdSSLIOHandlerSocketOpenSSL.Create(smtp);
      ssl.SSLOptions.SSLVersions := [sslvTLSv1];

      smtp.OnStatus := DoStatus;
      smtp.IOHandler := ssl;
      smtp.Host := FHost;
      smtp.Password := FPassword;
      smtp.Username := FUsername;
      smtp.UseTLS := utUseExplicitTLS;
      smtp.Port := 587;

      smtp.Connect;
      try
        smtp.Send(email);
      finally
        smtp.Disconnect;
      end;
    finally
      smtp.Free;
    end;
  finally
    email.Free;
  end;
end;

procedure TEmailThread.InitializeISO(var VHeaderEncoding: Char; var VCharSet: string);
begin
  ...
end;

procedure TEmailThread.DoStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
begin
  ...
end;

procedure SendAMail (const AFileName: string);
var
  host, user, pass: string;
begin
  repeat
    // this part gets the SMTP definitions from the database
    dm.qGetSMTP.Open;
    try
      host := dm.qGetSMTP.FieldByName('smtphost').AsString;
      username := dm.qGetSMTP.FieldByName('smtpuser').AsString;
      password := dm.qGetSMTP.FieldByName('smtppass').AsString;
    finally
      dm.qGetSMTP.Close;
    end;

    if (host <> '') and (user <> '') and (pass <> '') then
      Break;

    with TGetSMTP.Create(nil) do   // manage77a
    try
      Execute;
    finally
      Free;
    end;
  until False;

  TEmailThread.Create(AFileName, host, pass, user);
end;

end.
于 2013-03-18T00:29:28.180 に答える