sistemcrash
sistemcrash

Reputation: 35

Can't send email using Indy, freezes program

When i try to send an email with attachment using indy my program freezes and i don't know why. Here's the full code for the form i'm using for sending emails.

unit Dok_sutisana;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdMessage, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase,
IdSMTP, StdCtrls, Buttons, ComCtrls, IdAttachmentFile;

type
TForm14 = class(TForm)
  Edit1: TEdit;
  Edit2: TEdit;
  Label1: TLabel;
  Label2: TLabel;
  BitBtn1: TBitBtn;
FontDialog1: TFontDialog;
RichEdit1: TRichEdit;
IdSMTP1: TIdSMTP;
IdMessage1: TIdMessage;
BitBtn2: TBitBtn;
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
 end;

var
 Form14: TForm14;

 implementation

 uses Autentif, EDGA;

{$R *.dfm}

procedure TForm14.BitBtn1Click(Sender: TObject);
begin
if FontDialog1.Execute() then
RichEdit1.Font:=FontDialog1.Font;
end;

procedure TForm14.BitBtn2Click(Sender: TObject);
var s:string;
begin
form3.ADOTable1.Active:=true;
//setup SMTP
IdSMTP1.Host := form3.adotable1['smtp'];
IdSMTP1.Port := form3.adotable1['ports'];
IdSMTP1.Username:= '******@gmail.com';
IdSMTP1.Password:='******';

//setup mail message
IdMessage1.From.Address := form3.adotable1['e-pasts'];
IdMessage1.From.Name:= form3.adotable1['Vards']+' '+ form3.adotable1['Uzvards'];
IdMessage1.Recipients.EMailAddresses := edit1.Text;;

IdMessage1.Subject := edit2.Text;
IdMessage1.Body.Add(RichEdit1.Text + form3.ADOTable1['paraksts']);
s:= GetCurrentDir + form1.ADOTable1['Dok_adr'];
TIdAttachmentFile.Create(IdMessage1.MessageParts, s ) ;

//send mail

IdSMTP1.Connect() ;
IdSMTP1.Send(IdMessage1) ;
IdSMTP1.Disconnect;
IdMessage1.Free;
IdSMTP1.Free;

form3.ADOTable1.Active:=false;
Form14.Close;
end;

end.

I hope that whit this I can get some help for my problem.

Upvotes: 3

Views: 1338

Answers (2)

DavidG
DavidG

Reputation: 82

I deleted the use of ADO from your code and used hard-coded values for my email accounts (removed for security reasons here - you can the placeholders replace with working accounts).

This code works - it sends an attachment.

I also:

  • added a try / finally around the connection to ensure that it is released if the send throws an exception;
  • added the ConnectTimeout option mentioned by Lemy;
  • Cleared the email body. Before adding the new content (otherwise you end up with multiple copies of the test);
  • Need to remove the previous attachment as well otherwise your second email ends up with the attachment from the first

    IdSMTP1.Host := '******';
    IdSMTP1.Port := 25;
    IdSMTP1.Username:= '******@gmail.com';
    IdSMTP1.Password:='******';
    IdMessage1.From.Address := '******';
    IdMessage1.From.Name:= '******';
    IdMessage1.Recipients.EMailAddresses := '******';
    IdMessage1.Subject := '******';
    IdMessage1.Body.Clear; // Clear the email body
    IdMessage1.Body.Add('******');
    s:= GetCurrentDir + '\******';
    IdMessage1.MessageParts.Clear;
    TIdAttachmentFile.Create(IdMessage1.MessageParts, s ) ;
    
    IdSMTP1.ConnectTimeout := 2400 ;
    IdSMTP1.Connect();
    try
        IdSMTP1.Send(IdMessage1) ;
    finally
        IdSMTP1.Disconnect;
    end; 
    

As this simple example works, your problem could be:

  • incorrect email name / password / values from the table;
  • anti-virus package preventing your program access to TCP;
  • trying to use an email account not provided by your ISP

When I changed ISPs, the old one did not work (access requires SMTPS) but when I swapped to use the email account provided by my broadband supplier, this did not require SMTPS but worked on plain SMTP as it was inside their network and therefore trusted

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 596256

Indy uses blocking operations, and you are using Indy in the context of the main UI thread. So while TIdSMTP is busy, your main thread is blocked from processing new messages, giving the appearance of an app freeze, until TIdSMTP is finished.

To avoid the freezing, you can either:

  1. (preferred solution) Move your TIdSMTP code into a separate worker thread.

  2. Drop a TIdAntiFreeze component onto your Form. This will allow the main message queue to continue processing new messages while other Indy components are operating in the main thread.

For good measure, you should also set the TIdSMTP.ConnectTimeout and TIdSMTP.ReadTimeout properties so Connect() and Send() do not block for long periods of time. If a timeout occurs, an appropriate exception will be raised to abort the operation.

Upvotes: 3

Related Questions