Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Sending email


This question is not answered. Helpful answers available: 0. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Jul 26, 2017 10:04 AM Last Post By: Remy Lebeau (Te...
Jim Sawyer

Posts: 214
Registered: 1/3/10
Sending email  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 18, 2017 5:54 PM
Is there any way to troubleshoot Indy code for sending email?

I'm trying the following code after having tried about a dozen
routines previously, and am still having no luck. The most exasperating
thing about Indy is there seems to be no way to trace the problems.
Any way, if someone sees what I'm doing wrong (and I'm an Indy
novice) please give me a hint.

procedure TfrmEmailTest.btnSendEmailClick(Sender: TObject);
var
  AttachList: TStringList;
  tls: TIdUseTLS;
begin
  AttachList := NIL;
  if cbSSL.Checked then
    tls := utNoTLSSupport;
 
  if SendEmail( txtTo.Text,
                txtSubject.Text,
                 memoBody.Text,
                 AttachList,
                txtServer.Text,
                Round( numPort.Value ),
                txtFrom.Text,
                txtPassword.Text,
                tls ) then
      memoStatus.Text := 'Success'
    else
      memoStatus.Text := 'Failed!!!'
end;
 
procedure TfrmEmailTest.FormActivate(Sender: TObject);
begin
  Left := Screen.Width div 2 - Width div 2;
  Top := Screen.Height div 2 - Height div 2;
end;
 
procedure TfrmEmailTest.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  frmEmailTest := NIL;
end;
 
function TfrmEmailTest.SendEmail( sendTo: String;
                                  subject: String;
                                  body: String;
                                  attachFiles: TStringList;
                                  smtpHost: String;
                                  smtpPort: Integer;
                                  smtpUser: String;
                                  smtpPass: String;
                                  tls: TIdUseTLS ): Boolean;
var
  smtp: TIdSMTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  msg: TIdMessage;
  i: Integer;
begin
  smtp := TIdSmtp.Create( NIL );
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create( nil );
  msg := TIdMessage.Create( nil );
 
  try
 
    try
      smtp.Host := smtpHost;
      smtp.Port := smtpPort;
      smtp.Username := smtpUser;
      smtp.Password := smtpPass;
     
      if not ( tls = utNoTLSSupport ) then
      begin
        ssl.Destination := smtpHost + ':' + IntToStr( smtpPort );
        ssl.Host := smtpHost;
        ssl.Port := smtpPort;
        ssl.SSLOptions.Method := sslvTLSv1;
       
        smtp.IOHandler := ssl;
        msg.Subject := subject;
        msg.Body.Text := body;
      end;
 
      smtp.Connect;
      smtp.Send( msg );
      smtp.Disconnect();
 
      Result := true;
    finally
      msg.Free;
      ssl.Free;
      smtp.Free;
    end;
 
  except
    Result := false;
  end;
end;


Thanks,
Jim Sawyer
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Sending email
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 24, 2017 12:20 PM   in response to: Jim Sawyer in response to: Jim Sawyer
Jim Sawyer wrote:

Is there any way to troubleshoot Indy code for sending email?

Troubleshoot in what manner exactly?

I'm trying the following code after having tried about a dozen
routines previously, and am still having no luck.

What is the actual problem you are having?

The most exasperating thing about Indy is there seems to be no way to
trace the problems.

That is not true. For instance, you could attach one of the TIdLog...
components to TIdSMTP to log the actual SMTP commands and replies.
That will tell you which command is causing trouble, which will usually
be due to bad input in your code.

Any way, if someone sees what I'm doing wrong (and I'm an Indy novice)
please give me a hint.

I see several bugs in your code:

1. if your cbSSL CheckBox is not checked then your local 'tls' variable
is never assigned a value before being passed to SendEmail(). Local
variables do not have default values.

2. even if the CheckBox is checked, why would you set the variable to
utNoTLSSupport? That disables SSL/TLS. You should be using
utUseImplicitTLS or utUseExplictTLS instead, depending on the port you
are connecting to and what kind of handshake behavior the server
actually expects on that port.

3. if the tls variable is set to utNoTLSSupport, you are not assigning
any data to the TIdMessage's Subject and Body properties.

4. you are not setting the TIdSMTP.UseTLS property at all.

On a couple of side notes not related to your problem, I also see that:

1. 'if not ( tls = utNoTLSSupport ) then' should be coded as 'if ( tls
<> utNoTLSSupport ) then' instead.

2. Do not set the SSLIOHandler's Destination, Host, and Port properties
manually. They are set automatically by TIdSMTP.Connect().

3. why are you manually centering the Form on-screen in the OnActivate
event? You should just set the Form's Position property to
poScreenCenter instead and let it positition itself automatically for
you.

With that said, try something more like instead instead:

procedure TfrmEmailTest.btnSendEmailClick(Sender: TObject);
var
  port: Integer;
  tls: TIdUseTLS;
begin
  port := Round(numPort.Value);
 
  if cbSSL.Checked then
  begin
    if port = 465 then
      tls := utUseImplicitTLS
    else
      tls := utUseExplicitTLS;
  end else
    tls := utNoTLSSupport;
 
  if SendEmail( txtTo.Text,
                txtSubject.Text,
                memoBody.Text,
                nil,
                txtServer.Text,
                port,
                txtFrom.Text,
                txtPassword.Text,
                tls ) then
      memoStatus.Text := 'Success'
    else
      memoStatus.Text := 'Failed!!!'
end;
 
procedure TfrmEmailTest.FormActivate(Sender: TObject);
begin
  // consider removing this event handler entirely and set
  // the Form's Position property to poScreenCenter instead...
  Left := Screen.Width div 2 - Width div 2;
  Top := Screen.Height div 2 - Height div 2;
end;
 
procedure TfrmEmailTest.FormClose(Sender: TObject; var Action:
TCloseAction);
begin
  Action := caFree;
  frmEmailTest := NIL;
end;
 
function TfrmEmailTest.SendEmail( sendTo: String;
                                  subject: String;
                                  body: String;
                                  attachFiles: TStrings;
                                  smtpHost: String;
                                  smtpPort: Integer;
                                  smtpUser: String;
                                  smtpPass: String;
                                  tls: TIdUseTLS ): Boolean;
var
  smtp: TIdSMTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  msg: TIdMessage;
  i: Integer;
begin
  Result := false;
 
  try
    smtp := TIdSmtp.Create( NIL );
    try
      if ( tls <> utNoTLSSupport ) then
      begin
        ssl := TIdSSLIOHandlerSocketOpenSSL.Create( smtp );
        ssl.SSLOptions.Method := sslvTLSv1;
        smtp.IOHandler := ssl;
      end;
      smtp.UseTLS := tls;
 
      smtp.Host := smtpHost;
      smtp.Port := smtpPort;
      smtp.Username := smtpUser;
      smtp.Password := smtpPass;
      smtp.AuthType := satDefault;
 
      msg := TIdMessage.Create( smtp );
      msg.Subject := subject;
      msg.Body.Text := body;
 
      if attachFiles <> nil then
      begin
        for i := 0 to attachFiles.Count-1 do
          TIdAttachmentFile.Create( msg.MessageParts, attachFiles[i] );
      end;
 
      smtp.Connect;
      try
        smtp.Send( msg );
      finally
        smtp.Disconnect;
      end;
 
      Result := true;
    finally
      smtp.Free;
    end;
  except
  end;
end;


--
Remy Lebeau (TeamB)
Jim Sawyer

Posts: 214
Registered: 1/3/10
Re: Sending email  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2017 6:10 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Jim Sawyer wrote:

Is there any way to troubleshoot Indy code for sending email?

Troubleshoot in what manner exactly?

I guess what I need is a bit more information on why the thing won't connect
rather than just that it won't connect. Or why does it time out when trying
to connect. I get the error, but can rarely conclude what I should do with
the code. I don't think I've ever floundered so much with a part of a project
as with Indy. But with the help of people like you, I'll get there.


I'm trying the following code after having tried about a dozen
routines previously, and am still having no luck.

What is the actual problem you are having?

The most exasperating thing about Indy is there seems to be no way to
trace the problems.

That is not true. For instance, you could attach one of the TIdLog...
components to TIdSMTP to log the actual SMTP commands and replies.
That will tell you which command is causing trouble, which will usually
be due to bad input in your code.

Thanks. I'll try that this weekend.


Any way, if someone sees what I'm doing wrong (and I'm an Indy novice)
please give me a hint.

I see several bugs in your code:

1. if your cbSSL CheckBox is not checked then your local 'tls' variable
is never assigned a value before being passed to SendEmail(). Local
variables do not have default values.

2. even if the CheckBox is checked, why would you set the variable to
utNoTLSSupport? That disables SSL/TLS. You should be using
utUseImplicitTLS or utUseExplictTLS instead, depending on the port you
are connecting to and what kind of handshake behavior the server
actually expects on that port.

3. if the tls variable is set to utNoTLSSupport, you are not assigning
any data to the TIdMessage's Subject and Body properties.

4. you are not setting the TIdSMTP.UseTLS property at all.

On a couple of side notes not related to your problem, I also see that:

1. 'if not ( tls = utNoTLSSupport ) then' should be coded as 'if ( tls
<> utNoTLSSupport ) then' instead.

2. Do not set the SSLIOHandler's Destination, Host, and Port properties
manually. They are set automatically by TIdSMTP.Connect().

3. why are you manually centering the Form on-screen in the OnActivate
event? You should just set the Form's Position property to
poScreenCenter instead and let it positition itself automatically for
you.

With that said, try something more like instead instead:

procedure TfrmEmailTest.btnSendEmailClick(Sender: TObject);
var
  port: Integer;
  tls: TIdUseTLS;
begin
  port := Round(numPort.Value);
 
  if cbSSL.Checked then
  begin
    if port = 465 then
      tls := utUseImplicitTLS
    else
      tls := utUseExplicitTLS;
  end else
    tls := utNoTLSSupport;
 
  if SendEmail( txtTo.Text,
                txtSubject.Text,
                memoBody.Text,
                nil,
                txtServer.Text,
                port,
                txtFrom.Text,
                txtPassword.Text,
                tls ) then
      memoStatus.Text := 'Success'
    else
      memoStatus.Text := 'Failed!!!'
end;
 
procedure TfrmEmailTest.FormActivate(Sender: TObject);
begin
  // consider removing this event handler entirely and set
  // the Form's Position property to poScreenCenter instead...
  Left := Screen.Width div 2 - Width div 2;
  Top := Screen.Height div 2 - Height div 2;
end;
 
procedure TfrmEmailTest.FormClose(Sender: TObject; var Action:
TCloseAction);
begin
  Action := caFree;
  frmEmailTest := NIL;
end;
 
function TfrmEmailTest.SendEmail( sendTo: String;
                                  subject: String;
                                  body: String;
                                  attachFiles: TStrings;
                                  smtpHost: String;
                                  smtpPort: Integer;
                                  smtpUser: String;
                                  smtpPass: String;
                                  tls: TIdUseTLS ): Boolean;
var
  smtp: TIdSMTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  msg: TIdMessage;
  i: Integer;
begin
  Result := false;
 
  try
    smtp := TIdSmtp.Create( NIL );
    try
      if ( tls <> utNoTLSSupport ) then
      begin
        ssl := TIdSSLIOHandlerSocketOpenSSL.Create( smtp );
        ssl.SSLOptions.Method := sslvTLSv1;
        smtp.IOHandler := ssl;
      end;
      smtp.UseTLS := tls;
 
      smtp.Host := smtpHost;
      smtp.Port := smtpPort;
      smtp.Username := smtpUser;
      smtp.Password := smtpPass;
      smtp.AuthType := satDefault;
 
      msg := TIdMessage.Create( smtp );
      msg.Subject := subject;
      msg.Body.Text := body;
 
      if attachFiles <> nil then
      begin
        for i := 0 to attachFiles.Count-1 do
          TIdAttachmentFile.Create( msg.MessageParts, attachFiles[i] );
      end;
 
      smtp.Connect;
      try
        smtp.Send( msg );
      finally
        smtp.Disconnect;
      end;
 
      Result := true;
    finally
      smtp.Free;
    end;
  except
  end;
end;


--
Remy Lebeau (TeamB)

Thanks for the very helpful response.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Sending email
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2017 10:04 AM   in response to: Jim Sawyer in response to: Jim Sawyer
Jim Sawyer wrote:

I guess what I need is a bit more information on why the thing won't
connect rather than just that it won't connect.

Hard to say, as there are many different possibilities. I would start
with using a packet sniffer, like Wireshark, to see what is actually
happening with the network traffic.

Or why does it time out when trying to connect.

Usually, a timeout on connect is due to either an issue with DNS
resolution, lack of network connectivity to the target IP, or
mishandling of the protocol handshake after connecting to the target
(like waiting for data that never arrives because you are not sending
what the target is expecting you to send first). The last one is easy
to encounter if you misconfigure the UseTLS property, for instance.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02