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调用它的方式在您的线程中运行。当您运行TThreadExecute方法中的代码时,将在单独的线程中运行。但是,任何公共成员方法都可以像任何类的公共方法一样在实例上调用,并且它们在调用它们的线程上执行。

要使其正常工作,您需要让Execute方法执行调用以发送电子邮件。UI线程需要在Execute方法中触发动作,而不是自己执行动作;这可以通过多种方式来完成(与Execute同步WaitForSingleObject,通过消息传递等)。

您的其余代码看起来相当损坏。您的Execute代码不会真正按原样工作 - 这个循环:

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

永远不会终止,因为您似乎没有run在任何地方设置为 false 。此外,counter似乎没有在任何地方设置(我也不真正理解它的目的),所以这只会SendAllEmail()每 100 毫秒左右。

makeEmail函数将永远不会终止(堆栈溢出),因为它使用原始参数递归地调用自身,并且逻辑保证每次传递都重新进入。看起来它会在每次递归时发送任何消息 11 次(因为 11 的所有元素都Messagesnil在初始化之后和每次调用SendAllEmail().

即使您解决了这个问题 - 如果您是makeEmail从外部调用(即:从 UI 或另一个线程),那么这可能最终会出现各种跨线程错误,因为Execute调用线程和调用线程都将尝试同时SendAllEmail调用. 这段代码需要一些工作。

于 2013-05-08T05:42:41.403 回答