2
votes

Using Delphi XE2, Indy 10 that ships with it and OpenSSL dll's version 1.0.1c.

We are in the final stages of converting our Delphi 6 project to Delphi XE2.

We have solved every show stopper so far but I am running into one trying to connect to Gmail smtp server.

Our Delphi 6 app works fine using SSL v2.3 and SSL v3 and Indy 9 components connecting to port 465 per Google's own documentation. Google Support

Our Delphi XE2 app does not connect at all. The call to connect goes into the ether and nothing happens for some 7 minutes until I get bored waiting for the thing to timeout and kill it off. I actually traced the program execution all the way to the IdWinsock2 funcion here:

function Stub_select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): Integer; stdcall;
begin
  @select := FixupStub(hWinSockDll, 'select'); {Do not Localize}
  Result := select(nfds, readfds, writefds, exceptfds, timeout);//<-this line never returns and timeout is always nil
end;

I need to maintain the old SSL connectivity for existing users' configurations.

New users will be able to connect using TLS (to port 587) and that DOES work!?!?

I am at a loss as to why the non-TLS SSL options do not work and do not report any error and do not time out but just go off to Never-Never Land. Please help!

TJ

Here is the code:

  SMTPClient.Host := trim(EditSMTPServer.Text);
  SMTPClient.Port := EditSMTPServerPort.AsInteger;//<- value from custom edit box
  SMTPClient.Username := trim(EditSMTPLogon.Text);
  SMTPClient.Password := trim(EditSMTPPassword.Text);
  SMTPClient.AuthType := satDefault;

  if CheckBoxUseSSL.Checked then begin
    SMTPClient.IOHandler := IdSSLIOHandlerSocket1;
    IdSSLIOHandlerSocket1.ReadTimeout := 30000;//30 second timeout which does not appear to work
    case ComboBoxSSLMode.ItemIndex of
      0 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv2;
      1 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv23;
      2 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv3;
      3 : begin
        IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLsv1;
        SMTPClient.UseTLS := utUseImplicitTLS;
      end;
    end;//case
    IdSSLIOHandlerSocket2.SSLOptions.Method := IdSSLIOHandlerSocket1.SSLOptions.Method;
    IdSSLIOHandlerSocket2.PassThrough := False;
  end
  else begin
    SMTPClient.IOHandler := nil;
  end;

  try
    SMTPClient.Connect;
    if SMTPClient.Connected then begin
      if SMTPClient.Authenticate then begin
      ... do some work ...
      end;
    end;
  except
    on e:Exception do begin
      showmessage(e.message);
    end;
  end;

EDIT:

As usual, after I post a question I have stumbled across a workaround.

If I set the UsetTLS property to utUseImplicitTLS for all NON-SSL transactions and set it to utUseExplicitTLS for TLS transactions my connections appear to work in a timely manner.

Hopefully this helps someone out.

updated code:

if CheckBoxUseSSL.Checked then begin
  SMTPClient.IOHandler := IdSSLIOHandlerSocket1;
  SMTPClient.UseTLS := utUseImplicitTLS;
  case ComboBoxSSLMode.ItemIndex of
    0 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv2;
    1 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv23;
    2 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv3;
    3 : begin
      IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLsv1;
      SMTPClient.UseTLS := utUseExplicitTLS;
    end;
  end;//case
  IdSSLIOHandlerSocket2.SSLOptions.Method := IdSSLIOHandlerSocket1.SSLOptions.Method;
  IdSSLIOHandlerSocket2.PassThrough := False;
end
else begin
  SMTPClient.UseTLS := utNoTLSSupport;//reset TLS support flag
  SMTPClient.IOHandler := nil;
end;
1

1 Answers

3
votes

What you discovered is what you are supposed to be doing. SSL and TLS have different semantics, so you have to set UseTLS accordingly.

For SSL on port 465, the server expects your client to initiate an SSL handshake immediately upon connecting, before the server then sends an encrypted Greeting. UseTLS=utUseImplicitTLS does that, but UseTLS=utUseExplicitTLS does not. When UseTLS=utUseExplicitTLS, TIdSMTP will expect the server to send an unencrypted Greeting immediately, which would explain the hang in select() - the server is not sending any data!

For TLS on port 587, the server is expecting the client to connect initially unencrypted and then send an explicit STARTTLS command when it is ready to initiate encryption. UseTLS=utUseExplicitTLS does that, but UseTLS=utUseImplicitTLS does not.