Timestop
Timestop

Reputation: 73

Using INDY 10 with Exchange SMTP-Server

From a previous question here I learned how to use INDY SMTP (TIdSMTP) to send mails with an Office 365 account. I also figured it out for many others and it works for nearly any common e-mail provider out there. But I can't figure out how to use it with my local Exchange Server. Some time ago there were SASL-NTLM components shipped with indy, but it seems they have been removed. I need NTLM to connect to a local Exchange Server. But I can't figure out how to do this without NTLM.

Upvotes: 0

Views: 2882

Answers (1)

Dennis van Opzeeland
Dennis van Opzeeland

Reputation: 11

I have recently struggled with Indy and my Exchange server as well. The SaslNtlm component is not in the version of Indy10 shipped with Delphi XE5. It is not even in the source files of the Indy Protocols folder.

Fortunately a lot of the stuff required to do NTLM authentication with the SMTP client is available. There is a unit called IdAuthenticationSSPI which implements the entire NTLM exchange. All that was left to do was to implement a custom descendant from TIdSASL which interacts with the TIndySSPINTLMClient object.

  TSaslNtlm = class(TIdSASL)
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;

    function StartAuthenticate(const AChallenge, AHost, AProtocolName : string): string; override;
    function ContinueAuthenticate(const ALastResponse, AHost, AProtocolName : string): string; override;
    function IsReadyToStart: Boolean; override;

    class function ServiceName: TIdSASLServiceName; override;

  private
    FSSPIClient: TIndySSPINTLMClient;
  end;

The implementation of the class is as follows:

constructor TSaslNtlm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSSPIClient := TIndySSPINTLMClient.Create;
end;

destructor TSaslNtlm.Destroy;
begin
  FSSPIClient.Free;
  inherited;
end;

function TSaslNtlm.StartAuthenticate(const AChallenge, AHost,
                                     AProtocolName: string): string;
begin
  FSSPIClient.SetCredentials(AHost, '', '');
  Result := BytesToStringRaw(FSSPIClient.InitAndBuildType1Message);
end;

function TSaslNtlm.ContinueAuthenticate(const ALastResponse, AHost,
                                        AProtocolName: string): string;
var LastMsg: TIdBytes;
begin
  LastMsg := ToBytes(ALastResponse, Indy8BitEncoding
                     {$IFDEF STRING_IS_ANSI}, Indy8BitEncoding{$ENDIF});
  Result := BytesToStringRaw(FSSPIClient.UpdateAndBuildType3Message(LastMsg));
end;

function TSaslNtlm.IsReadyToStart: Boolean;
begin
  Result := True;
end;

class function TSaslNtlm.ServiceName: TIdSASLServiceName;
begin
  Result := 'NTLM';
end;

And then it is simply a matter of adding this SASL mechanism to the SMTP client:

smtp.AuthType := satSASL;
ntml := TSaslNtlm.Create(smtp);
with smtp.SASLMechanisms.Add do begin
  DisplayName := ntlm.ServiceName;
  SASL := ntlm;
end;

Upvotes: 1

Related Questions