Arno, I think you addressed the problem correctly ;) All subsequent Connect() calls (except the first one) are located within the OnRequestDone event procedure, in case of RqType=smtpQuit. I now see this must be wrong.
For a safe reconnect, should the message below be posted from OnRequestDone or from OnSessionClose? I guess it's the latter because it would be triggered after RqType=smtpQuit, right? Does calling Abort() also call OnSessionClose? Michael > -----Original Message----- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED] > Behalf Of Arno Garrels > Sent: Wednesday, January 17, 2007 9:24 AM > To: ICS support mailing > Subject: Re: [twsocket] Still problems while sending SMTP > > > 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 > -- 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