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.
1 Answers
1
votes
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;
TIdSASLNTLM
component still exists, in theIdSASL_NTLM.pas
unit, it is simply not registered on the Component Palette by default, but you can instantiate it programmably in code. – Remy Lebeau