Recent

Author Topic: Sending email with Indy  (Read 3844 times)

lucamar

  • Hero Member
  • *****
  • Posts: 1991
Re: Sending email with Indy
« Reply #60 on: May 01, 2019, 10:57:04 pm »
It also shows the solution: caling unix.ReReadLocalTime before GetLocalTimeOffset.

Yes, I know, but WHEN should that be called?

Well, the docs say:
Quote
Note that on Linux/Unix, this information may be inaccurate around the DST time changes (for optimization). In that case, the unix.ReReadLocalTime unit must be used to re-initialize the timezone information.
and, for ReReadLocalTime:
Quote
To speed up conversion of epoch (UTC) time to local time, the timezone information is loaded only once, at program startup. Calling this routine re-reads the timezone information using current timezone settings.

It doesn't matter (much) because it's not a value that changes with frequency (hey, two times a year!) but to be absolutely sure it's never out of synch one should do something like:
Code: Pascal  [Select]
  1. function GetRealLocalTimeOffset: Integer;
  2. begin
  3.   unix.ReReadLocalTime; {ifdefed for UNIX, of course}
  4.   Result := GetLoaclTimeOffset;
  5. end;

In a normal application one could use a Timer and call RereadLocalTime every hour or so, but I guess that doesn't apply for a library like Indy :)
« Last Edit: May 01, 2019, 11:00:45 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 654
    • Lebeau Software
Re: Sending email with Indy
« Reply #61 on: May 02, 2019, 03:56:37 am »
to be absolutely sure it's never out of synch one should do something like:
Code: Pascal  [Select]
  1. function GetRealLocalTimeOffset: Integer;
  2. begin
  3.   unix.ReReadLocalTime; {ifdefed for UNIX, of course}
  4.   Result := GetLoaclTimeOffset;
  5. end;

Is that thread-safe, though?
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

lucamar

  • Hero Member
  • *****
  • Posts: 1991
Re: Sending email with Indy
« Reply #62 on: May 02, 2019, 07:28:24 am »
Is that thread-safe, though?

I haven't seen the implementation but probably not. It has to ask the system and only the gods know what the OS may decide to do while it is at it. :)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

justnewbie

  • Full Member
  • ***
  • Posts: 213
Re: Sending email with Indy
« Reply #63 on: May 19, 2019, 03:53:04 pm »
New question:
I want to send an email to some recipients. The email is the same for all, except a random number within it, it is unique (simplified example of course).
How can I send the same emails to all with this unique part inside (ie. how can I update only the message body part)?
This is my bad code:
Code: Pascal  [Select]
  1. ...
  2.  
  3. with TIdText.Create(MailMessage.MessageParts, nil) do
  4. begin
  5.       Body.Text := Memo1.Text;
  6.       ContentType := 'text/plain';
  7.       ParentPart := 0;
  8. end;  
  9.  
  10. ...
  11.  
  12. try
  13.   try      
  14.     SMTP.Connect;
  15.  
  16.     for i := 0 to ListBox1.Count - 1 do
  17.       begin
  18.         MailMessage.Recipients.EMailAddresses := ListBox1.Items[i];
  19.         Body.Text := Body.Text + InToStr(Random(1000)); // This line has no effect
  20.         SMTP.Send(MailMessage);        
  21.       end;
  22.  
  23.     except on E:Exception do
  24.       Memo2.Lines.Insert(0, 'ERROR: ' + E.Message);
  25.     end;
  26. finally
  27.   if SMTP.Connected then SMTP.Disconnect;
  28. end;
  29.  
  30. ...

Can you help me?
« Last Edit: May 19, 2019, 06:15:36 pm by justnewbie »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 654
    • Lebeau Software
Re: Sending email with Indy
« Reply #64 on: May 20, 2019, 08:01:53 am »
How can I send the same emails to all with this unique part inside (ie. how can I update only the message body part)?

Since you are putting the random number into a TIdText object, simply store a reference to that object in a local variable so you can refer back to it on each loop iteration, eg:

Code: Pascal  [Select]
  1. var
  2.   IdText: TIdText;
  3.   MyText: string;
  4.  
  5. ...
  6.  
  7. MyText := Memo1.Text;
  8.  
  9. IdText := TIdText.Create(MailMessage.MessageParts, nil);
  10. IdText.ContentType := 'text/plain';
  11. IdText.ParentPart := 0;
  12.  
  13. ...
  14.  
  15. for i := 0 to ListBox1.Count - 1 do
  16. begin
  17.   MailMessage.Recipients.EMailAddresses := ListBox1.Items[i];
  18.   IdText.Body.Text := MyText + IntToStr(Random(1000));
  19.   SMTP.Send(MailMessage);        
  20. end;
  21.  
  22. ...
« Last Edit: May 20, 2019, 08:04:58 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

justnewbie

  • Full Member
  • ***
  • Posts: 213
Re: Sending email with Indy
« Reply #65 on: May 20, 2019, 12:57:01 pm »
Thank you Remy, it solved the original issue.
But unfortunately generated a new one.
Now I cannot send attachments (it worked before this modification you gave).
Now I got a '... raised exception class 'External: SIGKILL'.'
What does cause this?
This is my code:
Code: Pascal  [Select]
  1. ...
  2.  
  3. IdText := TIdText.Create(MailMessage.MessageParts, nil);
  4. IdText.ContentType := 'multipart/alternative';
  5.  
  6. IdText.ContentType := 'text/plain';
  7. IdText.ParentPart := 0;
  8.  
  9. IdText.Body.LoadFromFile(sendHTMLFile);
  10. IdText.ContentType := 'text/html';
  11. IdText.ParentPart := 0;
  12.  
  13. if slAttachedFiles.Count > 0 then
  14.   begin
  15.     for i := 0 to slAttachedFiles.Count - 1 do
  16.       begin
  17.         if FileExists(slAttachedFiles[i]) then TIdAttachmentFile.Create(MailMessage.MessageParts, slAttachedFiles[i]);
  18.       end;
  19.   end;
  20.  
  21. MailMessage.ContentType := 'multipart/mixed';
  22.  
  23. ...
  24.  
  25. try
  26.   try      
  27.     SMTP.Connect;
  28.  
  29.     for i := 0 to ListBox1.Count - 1 do
  30.       begin
  31.         MailMessage.Recipients.EMailAddresses := ListBox1.Items[i];
  32.         IdText.Body.Text := MyText + IntToStr(Random(1000));
  33.         SMTP.Send(MailMessage);        
  34.       end;
  35.  
  36.     except on E:Exception do
  37.       Memo2.Lines.Insert(0, 'ERROR: ' + E.Message);
  38.     end;
  39. finally
  40.   if SMTP.Connected then SMTP.Disconnect;
  41. end;
  42.  
  43. ...
« Last Edit: May 20, 2019, 03:55:03 pm by justnewbie »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 654
    • Lebeau Software
Re: Sending email with Indy
« Reply #66 on: May 20, 2019, 06:50:56 pm »
Now I cannot send attachments (it worked before this modification you gave).
Now I got a '... raised exception class 'External: SIGKILL'.'
What does cause this?

Offhand, I see nothing in the code you have shown that can cause an SIGKILL signal. You are just going to have to debug your code line by line until you find the error.

However, I do see some mistakes (ie missing code) in the way you are managing the structure of the TIdMessage. I suggest you read the following blog articles on Indy's website, if you have not already done so yet:

HTML Messages

New HTML Message Builder class
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

justnewbie

  • Full Member
  • ***
  • Posts: 213
Re: Sending email with Indy
« Reply #67 on: May 20, 2019, 10:24:01 pm »
My code was made based on those webpages.
What are those missing parts? Cannot see them, I think my code is complete.
As I wrote, sending attachments before the modification was fine.
« Last Edit: May 20, 2019, 10:26:56 pm by justnewbie »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 654
    • Lebeau Software
Re: Sending email with Indy
« Reply #68 on: May 21, 2019, 09:27:40 pm »
My code was made based on those webpages.
What are those missing parts? Cannot see them, I think my code is complete.

The code you have shown is NOT complete, as it is not creating enough TIdText objects as required for your MIME emails.  The code you have shown is creating only 1 TIdText object, but you actually need 3 separate TIdText objects instead, eg:

Code: Pascal  [Select]
  1. IdAlternative := TIdText.Create(MailMessage.MessageParts, nil);
  2. IdText.ContentType := 'multipart/alternative';
  3.  
  4. IdPlainText := TIdText.Create(MailMessage.MessageParts, nil); // <-- add this!
  5. IdPlainText.ContentType := 'text/plain';
  6. IdPlainText.ParentPart := IdAlternative.Index;
  7.  
  8. IdHTML := TIdText.Create(MailMessage.MessageParts, nil); // <-- add this!
  9. IdHTML.Body.LoadFromFile(sendHTMLFile);
  10. IdHTML.ContentType := 'text/html';
  11. IdHTML.ParentPart := IdAlternative.Index;

Then your send loop can update IdPlainText.Body and IdHTML.Body as needed.

This is clearly explained in my blog articles.  So, either the code you have shown is really missing those extra steps, or you have simply not shown everything you are really doing.
« Last Edit: May 21, 2019, 09:30:32 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

justnewbie

  • Full Member
  • ***
  • Posts: 213
Re: Sending email with Indy
« Reply #69 on: May 22, 2019, 04:07:07 pm »
Remy, thank you very much! Your example solved the issue perfectly!  :)