Recent

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

justnewbie

  • Full Member
  • ***
  • Posts: 225
Sending email with Indy
« on: April 23, 2019, 01:42:52 pm »
Hi,

I'm trying to send email by using Indy and the Gmail as smtp.
Here is my code:
Code: Pascal  [Select]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  9.   ExtCtrls, IdSMTP, IdMessage, IdAttachment, IdAttachmentFile;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Bevel1: TBevel;
  17.     Bevel2: TBevel;
  18.     Bevel3: TBevel;
  19.     Button1: TButton;
  20.     SendMailButton: TButton;
  21.     edHost: TEdit;
  22.     edFrom: TEdit;
  23.     edTo: TEdit;
  24.     edCc: TEdit;
  25.     edSubject: TEdit;
  26.     edAttachment: TEdit;
  27.     MailMessage: TIdMessage;
  28.     SMTP: TIdSMTP;
  29.     Label1: TLabel;
  30.     Label2: TLabel;
  31.     Label3: TLabel;
  32.     Label4: TLabel;
  33.     Label5: TLabel;
  34.     Label6: TLabel;
  35.     Label7: TLabel;
  36.     Label8: TLabel;
  37.     meStatus: TMemo;
  38.     meMessage: TMemo;
  39.     procedure SendMailButtonClick(Sender: TObject);
  40.   private
  41.  
  42.   public
  43.  
  44.   end;
  45.  
  46. var
  47.   Form1: TForm1;
  48.   Attachment: TIdAttachment;
  49.  
  50. implementation
  51.  
  52. {$R *.lfm}
  53.  
  54. { TForm1 }
  55.  
  56. procedure TForm1.SendMailButtonClick(Sender: TObject);
  57. begin
  58.   meStatus.Clear;
  59.   //setup SMTP
  60.   SMTP.Host := edHost.Text;  //  smtp.gmail.com is here
  61.   SMTP.Port := 465;
  62.   //setup mail message
  63.   MailMessage.From.Address := edFrom.Text;
  64.   MailMessage.Recipients.EMailAddresses := edTo.Text + ',' + edCc.Text;
  65.   MailMessage.Subject := edSubject.Text;
  66.   MailMessage.Body.Text := meMessage.Text;
  67.   if FileExists(edAttachment.Text) then Attachment := TIdAttachmentFile.Create(MailMessage.MessageParts, edAttachment.Text);
  68.   //send mail
  69.   try
  70.     try
  71.       SMTP.Connect;
  72.       SMTP.Send(MailMessage);
  73.     except on E:Exception do
  74.       meStatus.Lines.Insert(0, 'ERROR: ' + E.Message);
  75.     end;
  76.   finally
  77.     if SMTP.Connected then SMTP.Disconnect;
  78.   end;
  79. end;
  80.  
  81. end.

Email is not sent and I got this error:
ERROR: Connection Closed Gracefully.
How should I fix it?
« Last Edit: April 23, 2019, 01:44:30 pm by justnewbie »

sstvmaster

  • Full Member
  • ***
  • Posts: 127
Re: Sending email with Indy
« Reply #1 on: April 23, 2019, 01:50:00 pm »
Did you have enabled external smtp usage in your google account and your smtp client is accepted via Oauth2?
Lazarus 2.0.4 x32
Lazarus 2.1.0 Trunk x32
OS Win 7 32bit

justnewbie

  • Full Member
  • ***
  • Posts: 225
Re: Sending email with Indy
« Reply #2 on: April 23, 2019, 01:52:36 pm »
Did you have enabled external smtp usage in your google account and your smtp client is accepted via Oauth2?
Sorry, I don't understand a single word from this.
How can I do these?

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Sending email with Indy
« Reply #3 on: April 23, 2019, 02:09:37 pm »
Did you have enabled external smtp usage in your google account and your smtp client is accepted via Oauth2?
Sorry, I don't understand a single word from this.
How can I do these?
You are not allowed to just use smtp.gmail.com with your normal username and password.

You can either implement OAuth2, which I imagine is beyond your skillset, or you need to use a "App password" instead of your normal gmail password.

You can create a App password for smtp.gmail.com here:
https://myaccount.google.com/apppasswords?utm_source=google-account&utm_medium=web

Choose "App" E-mail and Device "Windows-computer".

(Note that this "App" password is for your gmail-account)

justnewbie

  • Full Member
  • ***
  • Posts: 225
Re: Sending email with Indy
« Reply #4 on: April 23, 2019, 02:57:25 pm »
Pretty frustrating that one can find sample codes like this https://support.embarcadero.com/article/36054 and this https://www.thoughtco.com/sending-email-messages-with-attachments-1058124 and others, but nowhere mentioned that other "tricks" are also needed to get it working.  :(
And what about to use not use Gmail as SMTP, but my internet provider's SMTP?

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Sending email with Indy
« Reply #5 on: April 23, 2019, 04:25:14 pm »
... and others, but nowhere mentioned that other "tricks" are also needed to get it working.  :(
That's because they used to work fine. But Google keeps restricting the use because of security.

Quote
And what about to use not use Gmail as SMTP, but my internet provider's SMTP?
You probably can use your providers smtp just fine (with or without SSL and authentication).
But that depends on your provider. Not all providers supply an smtp and if they do, it's only accessible connected to that network (which you probably are unless you have a laptop and go on a vacation with it).

lucamar

  • Hero Member
  • *****
  • Posts: 2082
Re: Sending email with Indy
« Reply #6 on: April 23, 2019, 04:33:39 pm »
[...] but nowhere mentioned that other "tricks" are also needed to get it working.  :(

Simplifying a lot: SMTP, as its name implies, is a very simple protocol created in the days when the internet was all fun and giggles. In consequence, it was also not quite secure enough so email providers have been implementing other measures (OAuth, etc.) to make at least the login to their servers secure before you can even start an SMTP conversation and from there come the "tricks" you talk about. They are really login "tricks", not SMTP tricks.

Quote
And what about to use not use Gmail as SMTP, but my internet provider's SMTP?

That, of course, depends on the provider and the security measures they have implemented, if any. Although nowadays most of them require some kind of secure login for which you'll have to use some "trick" or other :)
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: 225
Re: Sending email with Indy
« Reply #7 on: April 23, 2019, 05:00:16 pm »
Thank you guys for the thoughts, I will try it yet before giving up totally.  ::)

justnewbie

  • Full Member
  • ***
  • Posts: 225
Re: Sending email with Indy
« Reply #8 on: April 23, 2019, 05:35:20 pm »
I just tried with the PHPMailer and it worked perfectly if I gave these values into it:
$mail->isSMTP();                                     
$mail->Host = 'smtp.gmail.com';                  
$mail->SMTPAuth = true;                               
$mail->Username = 'MY_GOOGLE_EMAIL_ADDRESS HERE';             
$mail->Password = 'MY_GOOGLE_PW HERE';                 
$mail->SMTPSecure = 'tls';                           
$mail->Port = 587;

Is it possible to use Indy with these data?
In my original code only the HOST and PORT have been given. And what about the other data (tls, auth)?
Can I use them as well as with the PHPMailer within the Indy SMTP?

Update: when I try to change (in Object Inspector) the UseTLS input in Indy SMTP from 'utNoTLSSupport' to any other TLS option, I got this error:
SSL IOHandler is required for this setting
« Last Edit: April 23, 2019, 05:47:32 pm by justnewbie »

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Sending email with Indy
« Reply #9 on: April 23, 2019, 05:52:14 pm »
I just tried with the PHPMailer and it worked perfectly if I gave these values into it:
In that case you still have your gmail account set to insecure.
That's ok, but if in the future you switch to 2-stage authentication it might stop working and you need to use the app-password method. Just a heads-up.

Quote
Is it possible to use Indy with these data?
Yes, it should be possible to use these settings.
(although not sure how in indy, I use Synapse)

You could try the example at https://forum.lazarus.freepascal.org/index.php/topic,18483.msg106986.html#msg106986
You do need to include the OpenSSL dll's.

john horst

  • Jr. Member
  • **
  • Posts: 53
    • JHorst
Re: Sending email with Indy
« Reply #10 on: April 23, 2019, 06:21:00 pm »
Your Pas code is using port 465 which is SSL, it might even be disabled by Google at this point.

Your PHP code is using port 587 which is TLS.

Code: Pascal  [Select]
  1. SMTP.Port := 465;

Code: PHP  [Select]
  1. $mail->SMTPSecure = 'tls';                          
  2. $mail->Port = 587;

I don't use Indy but you need to use TLSvX. Oauth2 is not a requirement. https://www.indyproject.org/2015/09/07/openssl-changes/

justnewbie

  • Full Member
  • ***
  • Posts: 225
Re: Sending email with Indy
« Reply #11 on: April 23, 2019, 06:28:11 pm »
Thank you guys for the inputs, now it is working!  :)

@rvk:
I added the TIdSSLIOHandlerSocketOpenSSL component to the form and set its port. After it I could change the UseTLS to 'utUseRequireTLS' in SMTP.

@john horst:
Indeed, I changed the port. Thanks!

justnewbie

  • Full Member
  • ***
  • Posts: 225
Re: Sending email with Indy
« Reply #12 on: April 23, 2019, 06:54:20 pm »
Guys, new challenge!  :)
I want to send more than 1 attached files and these files can be in different folders.
I'd like to have something similar thing than in Thunderbird (see picture).
I think a Memo or ListBox could be good for showing the selected files, but how can the program "remember" their path during send-process?
What would be the best approach?
« Last Edit: April 23, 2019, 06:55:53 pm by justnewbie »

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Sending email with Indy
« Reply #13 on: April 23, 2019, 08:04:58 pm »
I think a Memo or ListBox could be good for showing the selected files, but how can the program "remember" their path during send-process?
Create a TStringList with all the files you want to attach (including their path). Fill the TListBox according to this TStringList (in correct order) with only the filename. When the user wants to delete number index 2 of the TListBox, delete the TStringList[2] too. The TStringList will be the basis for sending the attachments.

justnewbie

  • Full Member
  • ***
  • Posts: 225
Re: Sending email with Indy
« Reply #14 on: April 23, 2019, 08:12:39 pm »
I think a Memo or ListBox could be good for showing the selected files, but how can the program "remember" their path during send-process?
Create a TStringList with all the files you want to attach (including their path). Fill the TListBox according to this TStringList (in correct order) with only the filename. When the user wants to delete number index 2 of the TListBox, delete the TStringList[2] too. The TStringList will be the basis for sending the attachments.
Yes, my idea was similar, thank you for the confirmation.
Maybe later when I will be so brilliant in Lazarus that I could make a new component, I will make a TMixedPathFilesListBox.  :D