2013-03-17 4 views
0

Я задал предыдущие вопросы о отправке писем с вложениями с Indy через GMail, и я рад сказать, что базовый код работает правильно. Однако я заметил, что отправка вложений занимает несколько минут, и в это время программа зависает (хотя я добавил компонент TIdAntiFreeze в программу). Я подумал, что было бы неплохо иметь электронное письмо, отправленное отдельным потоком, что позволяет программе реагировать.Отправка электронной почты с помощью Indy через отдельную тему

Мне не удалось найти код в Интернете, который показывает, как отправлять электронную почту из потока, поэтому мне пришлось написать собственный код, который работает только частично.

Я удалил компонент 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. 
+0

Поместите форму на [ '«TDataModule»'] (http://docwiki.embarcadero.com/RADStudio/XE3/en/Using_Data_Modules). В любом случае, никакого взаимодействия с графическим интерфейсом нет. –

ответ

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. 
+0

Выглядит хорошо! Я попробую это сегодня вечером. –

Смежные вопросы