0
votes

If I send a basic email via TidSMTP (ignore the try/finally blocks, this is just an example):

var
  SMTP : TidSMTP;
  MSG : TidMessage;
  LHandler : TIdSSLIOHandlerSocketOpenSSL;
begin
  SMTP := TIdSMTP.Create(nil);
  Msg := TIdMessage.Create(nil);
  LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

  Msg.Body.Text := 'Test Simple Email';
  Msg.Subject := 'Test Simple Email Subject';
  Msg.From.Address := '[email protected]';
  MSG.ContentType := 'text/html';
  Msg.Priority := mpHighest;

  SMTP.Host := 'smtp.server.com';
  SMTP.Username := '[email protected]';
  SMTP.Port := 587;
  SMTP.Password := 'testPassword';

  SMTP.IOHandler := LHandler;

  try
    with Msg.Recipients.Add do
    begin
      Address := '[email protected]'
    end;
    try
      SMTP.Connect;
      SMTP.Send(Msg);
      SMTP.Disconnect;
    finally
      Screen.Cursor := crDefault;
    end;
  finally
    LHandler.Free;
    Msg.Free;
    SMTP.Free;
  end;

And then call a DLL which makes an HTTPS request via TidHTTP:

var
  myHTTP : TIdHTTP;
  LHandler: TIdSSLIOHandlerSocketOpenSSL;
  FJSON : String;
  GetStr : String;
begin
  GetStr := URLEncode('6421 E ROAD, GREELEY,CO,80634');
  GetStr := 'https://maps.googleapis.com/maps/api/geocode/json?address=' + GetStr + '&key=' + 'someGoogleAPIKey';

  myHTTP := TIdHTTP.Create(nil);
  try
    LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    try
      LHandler.SSLOptions.SSLVersions := [sslvTLSv1_2];
      myHTTP.IOHandler := LHandler;
      try
        FJSON := myHTTP.Get(GetStr);
      except
        on E: Exception do
        begin
          raise
        end;
      end;

      showmessage(FJSON);
    finally
      LHandler.Free;
    end;
  finally
    myHTTP.Free;
  end;

And then try the email a second time, I'm receiving the error "Error creating SSL context", specifically "error:140A90F1:SSL routines: SSL_CTX_new: unable to load ssl2 md5 routines"

If I change this slightly by feeding in the TidSMTP component into the TidSSLIOHandlerSocketOpenSSL Create method:

  LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(SMTP);
  ...
  //SMTP.IOHandler := lHandler;

Then it works. But I can't use that. This is a completely stripped down version of the problem. In reality I'm using ReportBuilder (digital-metaphors) to send the email, and they don't allow one to send in the TidSMTP during the TidSSLIOHandlerSocketOpenSSL Create method.

This error does not happen when the HTTPS request is made within the same program as the SMTP request. Only when crossing into a DLL. This error does not happen if I do the HTTPS/DLL first and then SMTP. There is something happening during the first SMTP call that sets it up for the error down the road.

Should I take this over to Digital-Metaphors, or is there something going on during the HTTPS/DLL call that I could be doing better?

Assigning an Owner to a component does not solve your issue. That is strictly for memory management only, which is not your issue. You have multiple modules using OpenSSL, and one module is likely unloading OpenSSL from memory while the other module is still using it. OpenSSL doesn't work very well in DLLs when it comes to dynamic (un)loading, and Indy does use OpenSSL dynamically. One thing you could try is having your main app have Indy load OpenSSL at startup before it is actually needed, thus keeping OpenSSL alive for the life of the app, rather than (un)load it on an as-needed basis - Remy Lebeau
What's the preferred method of loading OpenSSL? Ideally I'd like to exhaust all of my options before ditching the DLL. - FLDelphi
You can call Indy's LoadOpenSSLLibrary() function in the IdSSLOpenSSL unit. - Remy Lebeau
Putting LoadOpenSSLLibrary() into my FormCreate, and UnLoadOpenSSLLibrary() into the FormDestroy did not work. BUT putting Load/UnLoad Open SSL in a try/finally block around the SMTP Connect, Send, and Disconnect process did work. I'm guessing that's not advisable behavior? - FLDelphi
You should not need to do that, no. Especially since TidSSLIOHandlerSocketOpenSSL calls LoadOpenSSLLibrary() internally for you (in the TIdSSLContext constructor). But if it works for you, so be it. I can't comment on why the other approach did not work for you, and I have no way to reproduce/debug it myself right now. - Remy Lebeau