0

indy10.0.52で別スレッドの別ユニットでメールを送りたい ソースコードはある

unit ThreadEmail;

interface

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

type
  TThreadEmail = class(TThread)
  private
    run      : boolean;
    counter  : Integer;
    target   : Integer;
    IdSMTP: TIdSMTP;
    IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
    Messages : Array [0..10] of TIdMessage;
    procedure checkRun();
  protected
    procedure Execute; override;
  public
    constructor Create(timerInS:Integer;host:string;port:integer;username,password:String;readTimeout : integer = 0);reintroduce;
    function expressSend(recipients,subject,body:string;from:String='';replayTo:String='') :boolean;
    function makeEmail(recipients,subject,body:string;from:String='';replayTo:String=''): boolean;
    procedure SendAllEmail();
  end;

implementation

constructor TThreadEmail.Create(timerInS:Integer;host:string;port:integer;username,password:String;readTimeout : integer = 0);
var b: byte;
begin
  inherited Create(False);
  Priority:= tpNormal;
  FreeOnTerminate:= True;

  IdSMTP := TIdSMTP.Create;
  IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create();
  for b:=low(Messages) to high(messages) do Messages[b] := nil;

  IdSMTP.IOHandler := IdSSLIOHandlerSocketOpenSSL;
  IdSMTP.UseTLS    := utUseImplicitTLS;
  IdSMTP.Host      := host;
  IdSMTP.Port      := port;
  IdSMTP.Username  := username;
  IdSMTP.Password  := password;

  IdSSLIOHandlerSocketOpenSSL.DefaultPort   := 0;
  IdSSLIOHandlerSocketOpenSSL.Destination   := host+':'+inttostr(port);
  IdSSLIOHandlerSocketOpenSSL.Host          := host;
  IdSSLIOHandlerSocketOpenSSL.MaxLineAction := maException;
  IdSSLIOHandlerSocketOpenSSL.Port          := port;
  IdSSLIOHandlerSocketOpenSSL.ReadTimeout   := readTimeout;
  IdSSLIOHandlerSocketOpenSSL.SSLOptions.Method  := sslvSSLv3;
  IdSSLIOHandlerSocketOpenSSL.SSLOptions.Mode    := sslmClient;

  run:=true;
  //target := timerInS*10;
end;

function TThreadEmail.expressSend(recipients,subject,body:string;from:String='';replayTo:String='') : boolean;
var IdMessage: TIdMessage;
begin
  Result := false;
  IdMessage := TIdMessage.Create();
  IdMessage.Recipients.EMailAddresses := recipients;
  IdMessage.Subject := subject;
  IdMessage.Body.Text := body;
  if from <> '' then IdMessage.From.Address := from;
  if replayTo <> '' then IdMessage.ReplyTo.EMailAddresses := from;
  try
    IdSMTP.Connect();
    IdSMTP.Send(IdMessage);
    Result := true;
  finally
    IdSMTP.Disconnect();
  end;
end;

function TThreadEmail.makeEmail(recipients,subject,body:string;from:String='';replayTo:String='') : boolean;
var b: byte;
begin
  Result := false;
  for b:=low(Messages) to high(messages) do
    if Messages[b] = nil then
    begin
      Result := true;
      Messages[b]:= TIdMessage.Create();
      Messages[b].Recipients.EMailAddresses := recipients;
      Messages[b].Subject := subject;
      Messages[b].Body.Text := body;
      if from <> '' then Messages[b].From.Address := from;
      if replayTo <> '' then Messages[b].ReplyTo.EMailAddresses := from;
    end;
  if not(result) then
  begin
    SendAllEmail();
    makeEmail(recipients,subject,body,from,replayTo);
  end;
end;

procedure TThreadEmail.SendAllEmail();
var b: byte;
begin
  try
    IdSMTP.Connect();
    for b:=low(Messages) to high(messages) do
      if run and (Messages[b] <> nil) then
      begin
        try
          IdSMTP.Send(Messages[b]);
        finally
          Messages[b].Free;
          Messages[b] := nil;
        end
      end;
    finally
      IdSMTP.Disconnect();
    end;
end;

procedure TThreadEmail.checkRun();
begin
  Dec(counter);
  if counter <= 0 then SendAllEmail();
end;

procedure TThreadEmail.Execute;
var b: byte;
begin
  while run do
  begin
    sleep(100);
    checkRun();
  end;
  IdSMTP.Free;
  IdSSLIOHandlerSocketOpenSSL.Free;
  for b:=low(Messages) to high(messages) do
    if Messages[b] <> nil then Messages[b].Free;
end;

end.

そして主に私が作成する

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,  ThreadEmail;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var   ThreadEmail : TThreadEmail;
begin
  ThreadEmail := ThreadEmail.Create(10,'smtp.gmail.com',465,'xxx.gmail.com','xxx',2000);
  ThreadEmail.expressSend('xxx@yahoo.com','TES','TES');
end;

button1 をクリックすると、常に「アクセス違反エラーの作成」が発生するのはなぜですか? 誰でも私を助けることができますか?情報として、以前にメールを送信することに成功しましたが、単独で実行できる単一ユニットを作成したいと考えています。ありがとう

4

1 に答える 1

5
ThreadEmail := ThreadEmail.Create(10,'s....

これは次のようになります。

ThreadEmail := TThreadEmail.Create(10,'s....

それが単なるタイプミスかどうかわかりませんか?そうしないと確実にAVになります。


いずれにせよ、呼び出している方法で のスレッドThreadEmail.expressSendで実行されません。TThread実行するTThreadと、そのExecuteメソッド内のコードは別のスレッドで実行されます。ただし、どのパブリック メンバー メソッドも、任意のクラスのパブリック メソッドと同じようにインスタンスで呼び出すことができ、呼び出し元のスレッドで実行されます。

これを機能Executeさせるには、電子メール メッセージを送信するための呼び出しを実行するメソッドが必要です。UI スレッドはExecuteメソッドでアクションをトリガーする必要があり、アクション自体を実行する必要はありません。これは、さまざまな方法で実行できます ( とのExecute同期WaitForSingleObject、メッセージ パッシングなど)。

コードの残りの部分はかなり壊れているように見えます。あなたのExecuteコードはそのままでは機能しません - このループ:

while run do
begin
  sleep(100);
  checkRun();
end;

runどこにも false に設定していないように見えるため、終了することはありません。さらに、counterどこにも設定されていないようです(また、その目的を本当に理解していません)ので、これはSendAllEmail()100ミリ秒ごとに行われます。

このmakeEmail関数は、元の引数を使用して再帰的に自身を呼び出し、パスごとに再入力が保証されるため、関数が終了することはありません (スタック オーバーフロー)。また、再帰のたびにメッセージを 11 回送信するようにも見えます ( の 11 個の要素はすべてMessages初期nil化後とSendAllEmail().

これを修正したとしても、外部から (つまり、UI または別のスレッドから) 呼び出している場合、呼び出し元のスレッドと呼び出し元のスレッドが同時に呼び出そうとするmakeEmailため、あらゆる種類のクロススレッド エラーが発生する可能性があります。. このコードにはいくつかの作業が必要です。ExecuteSendAllEmail

于 2013-05-08T05:42:41.403 に答える