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

Reply via email to