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