Regarding my last mail ('SMTP component not ready' exception), I learnt that the problem doesn't occur if I put the whole 'case RqType of: .. end;' into a try..except and simply ignore the exception.
But I'm not sure if this is the correct way to handle it. I fear to miss some real exceptions which I'm also suppressing this way, and I don't like much quiet exceptions for complex operations. How do you all handle such a situation? Michael > -----Original Message----- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED] > Behalf Of Kochendoerfer, Michael > Sent: Wednesday, January 17, 2007 3:29 PM > To: ICS support mailing > Subject: Re: [twsocket] Still problems while sending SMTP > > > Arno, > > now I implemented it all the way you suggested. I have a > message handler procedure, which decides whether a record > results in a mail or in a print job. It then calls either > smtpCli.Connect() or DoPrint() (own form method) accordingly. > > When it is a mail job and it has been processed, the > OnSessionClosed posts the handler message again. When it's a > print job, the very last line of DoPrint() posts the handler message. > > I'm starting the whole processing by an initial PostMessage() > to this handler procedure and write useful info into a log > memo and a file. And as you wrote earlier, there's another > RequestDone (smtpQuit) after a OnSessionClosed call. But even > if I don't have any direct calls to the message pump, my own > handler message is processed before the smtpQuit state occurs > in OnRequestDone, so the smtpCli.Connect() may take place > _before_ OnRequestDone has finished processing the previous > mail. This sometimes results in a SMTP component not ready exception. > > How can I prevent this situation from occuring? AFAIR, I > shouldn't have a loop somewhere testing for the component > state, so I need another mechanism to prevent it. > > All other things are fine now, thanks a lot ;) > > Michael > > > > -----Original Message----- > > From: [EMAIL PROTECTED] > > [mailto:[EMAIL PROTECTED] > > Behalf Of Arno Garrels > > Sent: Wednesday, January 17, 2007 10:55 AM > > To: ICS support mailing > > Subject: Re: [twsocket] Still problems while sending SMTP > > > > > > Kochendoerfer, Michael wrote: > > > 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? > > > > SessionClose is the right place to post the message and yes > Abort also > > triggers OnSessionClose. OnSessionClose fires when the connection is > > closed no matter who closed it, and that may occur at *ANY TIME*. > > Note that if a request is still pending OnRequestDone will be > > triggered afterwards as well. Calling Abort while the component is > > still waiting for a response or while it's sending data will cause > > OnRequestDone being triggered with an error code > 0, this was > > AFAIR (10053) Software caused connection abort. > > > > --- > > Arno Garrels [TeamICS] > > http://www.overbyte.be/eng/overbyte/teamics.html > > > > > > > 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 > > > -- > 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