Recent

Author Topic: LNet SMTP  (Read 15209 times)

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« on: April 04, 2008, 01:48:10 pm »
Hi Guys

I am trying to use LNet's SMTP component to send automated emails from my application.

It seems to connect just fine but the message never actually goes. I am using a modified version of the example (which won't compile because it can't find win32int used by LCLNet.)

Any assistance would be appreciated. Any links to suitable examples from which I can learn and fix this would also be appreciated.

Regards
Andrew

Almindor

  • Sr. Member
  • ****
  • Posts: 412
    • http://www.astarot.tk
RE: LNet SMTP
« Reply #1 on: April 04, 2008, 08:07:08 pm »
Hello, there's a Lazarus problem with saving .lpi file it seems. The example in lNet is ok, but you need to go to project/compiler options and set the widgetset to win32.

At least I presume you're in windows?

As for the problem, if it persists, please paste the Log (in my example is located in Help/Log) so I can see what the server said.

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #2 on: April 08, 2008, 04:49:44 pm »
Thanks Almindor2.

That fixed the problem with compiling the example.

I still can't seem to get my own application to send. Are there any particular "gotcha"s I need to keep an eye open for? I used the code from the example almost verbatim, just removed the button click to automate the process.

Regards
Andrew

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #3 on: April 10, 2008, 08:00:53 am »
I have it working now thanks. Well partially.

I am running through a list and sending an email for each item. Do I need to make sure that an email message was sent before sending the next one? Because I am only getting two of twenty five attempts.

Regards
Andrew

windy

  • Full Member
  • ***
  • Posts: 186
LNet SMTP
« Reply #4 on: April 11, 2008, 11:15:25 am »
Hi
you could instead try using synapse instead....I have that working OK :)

Almindor

  • Sr. Member
  • ****
  • Posts: 412
    • http://www.astarot.tk
LNet SMTP
« Reply #5 on: April 12, 2008, 01:01:04 pm »
Are you sending same mail to multiple recepients or sending a different mail 20 times?

In case of 1st, just add them all to the recipients (divider is ,). In case of second, you need to wait for RST to finish (happens after the mail is set) and if you want to be sure it got sent ok (eg: no problems from server, like lack of authorisation etc.) then you need to watch for DATA event's success.

To do that, make sure the StatusSet property has ssData and ssRset set to true. Then assign a OnSuccess (and optionally OnFailure) events in which you react. Once ssRset is successful, you can issue next mail sending.

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #6 on: April 12, 2008, 07:36:26 pm »
Hi Almindor2

Thanks. I thought as much but can't seem to get it to work. What I am doing is on a form create I open a file which is effectively a list of email addresses and store codes. I cycle through these opening a file with the store code in the name. I read this file in and produce an email based on it.

When I open the store codes file I set a variable (MessageSent) to False. Then on SMTP.OnSuccess I check the status and if it is ssRset or ssData I set MessageSent to True.

Code: [Select]
procedure TfrmMail.Create()

begin
  while not eof(SC) do
    begin
      if FirstTime then
        begin
          MessageSent := True;
          FirstTime := False;
        end;

//DO SOME OTHER WORK AND GENERATE MESSAGE BODY ETC

      repeat
        Application.ProcessMessages;
        Sleep(10);
      until
        MessageSent = True;
      smtp.SendMail(From, Email, Subject, FMimeStream);
    end;

procedure TfrmMail.smtpSuccess(aSocket: TLSocket;
  const aStatus: TLSMTPStatus);
begin
  case aStatus of
    ssRset: begin
              MessageSent := True;
              MessageDlg('Message sent successfuly', mtInformation, [mbOK], 0);
            end;
    ssData: begin
              MessageSent := True;
              MessageDlg('Message sent successfuly', mtInformation, [mbOK], 0);
            end;
    ssQuit: begin
              smtp.Disconnect;
              if TimerQuit.Enabled then
                Close;
            end;
  end;
end;


But it never seems to move to the next line of the store codes (SC) file. Am I doing something really dumb? Quite possible. :-)

Any further assistance would be appreciated.

Regards
Andrew

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #7 on: April 12, 2008, 07:37:46 pm »
Quote from: "windy"
Hi
you could instead try using synapse instead....I have that working OK :)


Thanks Windy. I will look into this if I don't come right.

Regards
Andrew

Almindor

  • Sr. Member
  • ****
  • Posts: 412
    • http://www.astarot.tk
LNet SMTP
« Reply #8 on: April 13, 2008, 12:58:15 pm »
The problem is that you're locked in a cycle. I'm not sure if Application.ProcessMessages is enough for lNet to work. You mustn't do this in a blocking cycle. In other words you can't do a loop in one of the events (of form or anything for that matter) because that means that the GUI doesn't get a chance to process sockets (in visual version, lNet makes use of the widgetset to watch the sockets).

What you need to do is this:
1. based on some event (can be on form create, or a button or whatever initially), read the 1st part of your file, compose a mail and send it
2. wait for OnSuccess with Status = ssRset, when that happens, read next mail and send again (could be same procedure somewhere for simplicity)
3. once the last mail is read/send, then set some variable to the next OnSuccess doesn't try to send the next one

so something like this: (pseudocode)
Code: [Select]

procedure Form.OnCreate;
begin
  Finished := False; // wether we read all mails
  PrepareMailFile; // opens the file for reading etc. how you do it, if a filestream or something else is irrelevant
  SendNextMail;
end;

procedure Form.SendNextMail;
var
  mail: TMail;
begin
  try
  { reads next mail from the mails file, composes it into TMail for example, sets Finished to True if no more mails can be read (EOF = true or so) }
    mail := GetNextMail;
    if Assigned(mail) then // if there was a mail still in the file
      SMTP.SendMail(mail); // send the mail
  finally
    mail.Free; // don't forget to free  :)
  end;
end;

procedure Form.SMTPSuccess(const aStatus: TLSMTPStatus);
begin
  case aStatus of
    ssRset: if not Finished then SendNextMail; // if we still were able to read a mail from the file, send it
    ssData: Log('Successfully sent a mail'); // could be "which mail" or more specific of course, just for illustration
  end;
end;

procedure Form.OnFailure(const aStatus: TLSMTPStatus);
begin
  case aStatus of
    ssData: Log('Mail sending failed'); // possibly stop the loop, set finished to true etc.
  end;
end;


So basically, you read data from file, compose a TMail out of them and then send it, and when sending is finished you repeat the whole thing until the last mail is sent.

This has also the advantage that it won't block your GUI (not sure if Application.ProcessMessages is enough to be completely non-blocking for gui stuff).

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #9 on: April 13, 2008, 06:47:19 pm »
Thanks Almindor2. I will give this a try tomorrow. I appreciate your efforts in teaching me how to code. :-)

Regards
Andrew

Almindor

  • Sr. Member
  • ****
  • Posts: 412
    • http://www.astarot.tk
LNet SMTP
« Reply #10 on: April 13, 2008, 08:35:55 pm »
Heh, well lNet in it's goal of being completely threadless has a few "quirks" which can seem limiting. The above problem of "won't work if you're in a loop" is one such nice example. On the bright side, if something goes wrong you won't find yourself in a race condition :)

In case you don't need a visual form for your program, I'd suggest to put things into a console app and use the lnetbase stuff. Instead of Application.ProcessMessages you would simply do SMTP.CallAction (you can specify a timeout so no need for Sleep() either) and your old code should work (of course you'd need to create the classes manualy then, also make the callbacks without the OI help etc.). Note that .CallAction is only valid for non-visual lNet stuff, it doesn't do anything on any of the TL*component (because it can't).

Ales

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #11 on: April 14, 2008, 12:22:20 pm »
Hi Ales,

I can't seem to get any response when checking status ssRset onSuccess. I must be missing something before I try to SendMail.

Can I perhaps contact you off the forum (I have your gmail address) to discuss this further? Perhaps I can get  hold of you on ICQ later?

Regards
Andrew

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #12 on: April 14, 2008, 08:36:04 pm »
Hi Ales

I have come right thanks. Perhaps a very basic 'mistake' :oops: , but I thought I would note it here as it may help others.

I had to set the StatusSet to include ssRset before I could use it. I assume the component only reports the status if it is set to true in StatusSet.

As I said. Perhaps a basic 'mistake' but maybe someone else will find their solution a bit easier now.

Thanks to all those who helped. Especially Almindor2. Great component.

Regards
Andrew Higgs

Almindor

  • Sr. Member
  • ****
  • Posts: 412
    • http://www.astarot.tk
LNet SMTP
« Reply #13 on: April 15, 2008, 11:17:49 am »
Yeah, it has to be set (I mentioned this in the upper post, but it's understandable you missed it). The StatusSet is a sort of filter where you say which SMTP commands do you want to watch via OnSuccess and OnFailure events. I guess enabling them all by default might be better than having them set to false :)

andrew.higgs

  • New Member
  • *
  • Posts: 22
LNet SMTP
« Reply #14 on: April 15, 2008, 02:39:41 pm »
Sorry. My bad. :-) On by default might be a good idea.

Thanks.

 

TinyPortal © 2005-2018