In order to reconnect safely you need to get out of your loop
after the session has been closed AND after OnRequestDone 
has been triggered RqType smtpQuit as well. You must assign event
OnSessionClose to always get notified about connection close,
this can happen before as well as after OnRequestDone triggered
RqType smtpQuit, I'm not sure if you do something like that. 

In order to get out of your loop just post a custom message,
something like: 

PostMessage(Form1.Handle, WM_MAILSENT, Integer(Something), Integer(Something));

The message handler is declared like:

const
  WM_MAILSENT = WM_USER + 1;
..
protected
  procedure WmMailSent(var Msg: TMessage); message WM_MAILSENT;
..   

procedure TForm1.WmMailSent(var Msg: TMessage);
begin
  Display(IntToStr(Msg.WParam) + ' ' + IntToStr(Msg.LParam); 
  ..  
  In the message handler you can connect safely again.
  SmtpCli.Connect;
end;


---
Arno Garrels [TeamICS]
http://www.overbyte.be/eng/overbyte/teamics.html



Michael Kochendoerfer wrote:
> Arno and all,
> 
> I realized and appreciated your hint to perform it all event-driven
> and I tried to accomplish it the way you suggested. However, I have
> some problems building the correct logic, it seems. In short words,
> the mail sending part of my application is as follows:
> 
> 1. Opening a SQL server query
> 2. Fill the standard properties (like Host, Port etc.) which are
> common between calls
> 3. Invoking my OnGetNextMailParam notify procedure *directly*, as if
> it had been called from the OnRequestDone handler
> 3a. OnGetNextMailParam checks if the query has still records, read
> some fields, sets HdrTo if the record contains an mail address, calls
> Connect() and Next() for the query
> 3b. OnGetNextMailParam calls a message handler procedure if there's no
> target mail address, which invokes 3 again.
> 4. OnRequestDone is built like the sample code in MailSnd1.pas, except
> for the smtpQuit part. In my handler, OnGetNextMailParam is called
> again, and if it reports a valid target address, it calls Connect()
> again (if not, it should have been handled by 3b)
> 
> This all should work from the beginning of the query to the end, where
> each record containing a target address should invoke the sending
> process and each other record should not (records without an mail
> address are handled otherwise). But it doesn't - it calls Connect()
> for two records and then it leaves.
> 
> I don't like you all to analyze my procedures but I'm looking for some
> basic framework which would do it. I first thought of building the
> whole procedd into the smtpConnect part of OnRequestDone, but this
> isn't possible due to the lack of mail addresses in some of the
> records. I'm really stuck here and I now realize my concept won't
> work as needed. 
> 
> The whole thing is not more or less than walking through a record set
> and sending a mail to each receiver within that record set having a
> mail address. Other records having no mail address are handled
> otherwise, must be processed within the same loop but don't invoke
> any mail sending process. And - of course - it should be async ;)
> 
> TIA,
> Michael
> 
> 
> Arno Garrels schrieb:
> 
>>> while not FlagDone do begin
>>>  //Application.ProcessMessages;  // Don't know whether or not to use
>>> the message pump here   Sleep(50);
>>> end;
>>> 
>>> 
>> 
>> This is bad design. Do not wait in a loop. While sleeping the calling
>> thread is blocked. Instead let your derived component do the work in
>> the background. In order to get notified when the job has finished
>> add a custom event that fires when the work is done, or may be add
>> another custom event that notifies the application when a single
>> message has been sent/failed. In other words, control the
>> application completely thru events while executing the mailing. So
>> in the ButtonClick handler there the call to start the mailing
>> should be the very last line. 
>> 
>> ---
>> Arno Garrels [TeamICS]
>> http://www.overbyte.be/eng/overbyte/teamics.html
>> 
>> 
>> Kochendoerfer, Michael wrote:
>> 
>> 
>>> You all are giving excellent information in this mailing list,
>>> thanks a lot!
>>> 
>>> I guess my problem is - as you describe - that the component is
>>> still active, even if smtpQuit has been reached within
>>> OnRequestDone. I don't currently check if it's still connected, but
>>> I will change it. Errors will be checked and force to abort the
>>> entire mail and write some log entries.
>>> 
>>> As Arno said earlier, I'd like to have async components because of
>>> their benefits. But in fact, for me it is a sync call, at least for
>>> each single mail. IOW, I've to wait until each particular mail has
>>> been finished before I'm advancing to the next one. So I'm starting
>>> with Connect(), let the OnRequestDone do the background stuff and
>>> set a flag if either aborted or quit. Now I know I've to wait also
>>> for not Connected. But what's the correct method to wait for
>>> completion? Currently, I have a loop after calling Connect()
>>> looking like this: 
>>> 
>>> while not FlagDone do begin
>>>  //Application.ProcessMessages;  // Don't know whether or not to use
>>> the message pump here   Sleep(50);
>>> end;
>>> 
>>> Any thoughts?
>>> 
>>> TIA,
>>> Michael
>>> 
>>> 
>>> 
>>> 
>>>> -----Original Message-----
>>>> From: [EMAIL PROTECTED]
>>>> [mailto:[EMAIL PROTECTED]
>>>> Behalf Of DZ-Jay
>>>> Sent: Tuesday, January 16, 2007 10:57 AM
>>>> To: ICS support mailing
>>>> Subject: Re: [twsocket] Still problems while sending SMTP
>>>> 
>>>> 
>>>> 
>>>> On Jan 16, 2007, at 02:49, Arno Garrels wrote:
>>>> 
>>>> 
>>>> 
>>>>> When the response to the Quit command is received the connection
>>>>> (may) still be alive. So watch both, whether Quit response has
>>>>> been received as well as the SessionClose event. Call connect only
>>>>> after the session has been closed.
>>>>> Don't start a loop directly from an event handler but post a
>>>>> custom message to some Window, in it's message handler start the
>>>>> next loop. 
>>>>> 
>>>>> 
>>>> You could, in fact, re-use the connection if the next message
>>>> is to be
>>>> sent through the same server.  All you have to do is, after the
>>>> DATA command is completed and the server acknowledges receipt,
>>>> check SmtpCli.Connected, if you are still connected then reset your
>>>> state-machine to start the cycle fromthe MAIL FROM command.  Some
>>>> servers required a "reset" (RSET) command be sent to reset state,
>>>> and it doesn't hurt to send it anyway.  The important thing is to
>>>> check the
>>>> connection, because something may have happened -- and indeed, some
>>>> servers have anti-spamming filters that will kick you out after
>>>> receiving DATA that they determine is spam, and some won't
>>>> allow you to
>>>> re-send after one message.  So the algorithm would be something
>>>> like: 
>>>> 
>>>> 1. Connect
>>>> 2. HELO
>>>> 3. MAIL FROM
>>>> 4. RCPT TO
>>>> 5. DATA
>>>> 6. If connected:
>>>> 6.a (yes) RSET then back to 3
>>>> 7. QUIT
>>>> 8. back to 1
>>>> 
>>>> Of course, you should check for errors after each step (in
>>>> OnRequestDone, before changing states).  Keep in mind that
>>>> some errors
>>>> are recoverable (transient: 400+), some errors are not
>>>> (non-transient:
>>>> 500+), and some are somewhere in between (like RCPT warnings, etc).
>>>> Recoverable errors allow you to try again, or require a RSET
>>>> and start
>>>>> from step 3, while non-transient errors require closing the
>>>> connection
>>>> and starting from scratch.  If you are sending general messages to
>>>> strange servers "in the wild" it gets pretty complicated, specially
>>>> when you factor in all the non-RFC-compliant servers; but if your
>>>> application is of limited purpose, sending using the same server
>>>> all the time, the errors and issues that may occur are predictable
>>>> and substantially less.
>>>> 
>>>> Building this logic in a simple state-machine using
>>>> OnRequestDone makes
>>>> it fairly easy to make your application powerful and efficient --
>>>> the reason we always push for the use of async methods.
>>>> 
>>>> dZ.
>>>> 
>>>> --
>>>> DZ-Jay [TeamICS]
>>>> http://www.overbyte.be/eng/overbyte/teamics.html
>>>> 
>>>> --
>>>> To unsubscribe or change your settings for TWSocket mailing list
>>>> please goto http://www.elists.org/mailman/listinfo/twsocket
>>>> Visit our website at http://www.overbyte.be
-- 
To unsubscribe or change your settings for TWSocket mailing list
please goto http://www.elists.org/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be

Reply via email to