Using INDY 10 SMTP with Office365 - delphi

I'm not familar with the INDY SMTP component. I want to send a mail with INDY and Office 365. Here is a nice topic which helped me a lot: What do the SMTP Indy component security and authentication properties do?
But I did not figured out how to use SASL. Office365 adress is smtp.office365.com with port 587 and TLS. So I added an SMTP and an OpenSSL-IOHandler to my form and setted the properties. But I didn't work, the app is just freezing. I need to know how to use SASL with Office365.
Thanks.

Office365 only supports the LOGIN SASL on TLS port 587.
The following code works fine for me when I just tried it (all of these settings can also be set up at design-time as well):
setting the TIdSMTP.AuthType property to satDefault, which uses the SMTP AUTH LOGIN command:
var
idSMTP1: TIdSMTP;
begin
idSMTP1 := TIdSMTP.Create(nil);
try
idSMTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(idSMTP1);
idSMTP1.UseTLS := utUseExplicitTLS;
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvSSLv3;
idSMTP1.Host := 'smtp.office365.com';
idSMTP1.Port := 587;
idSMTP1.AuthType := satDefault;
idSMTP1.Username := ...;
idSMTP1.Password := ...;
try
idSMTP1.Connect;
try
idSMTP1.Authenticate;
finally
idSMTP1.Disconnect;
end;
ShowMessage('OK');
except
on E: Exception do
begin
ShowMessage(Format('Failed!'#13'[%s] %s', [E.ClassName, E.Message]));
raise;
end;
end;
finally
idSMTP1.Free;
end;
setting the TIdSMTP.AuthType property to satSASL and using TIdSASLLogin, which uses the same SMTP AUTH LOGIN command:
var
idSMTP1: TIdSMTP;
idSASLLogin: TIdSASLLogin;
idUserPassProvider: TIdUserPassProvider;
begin
idSMTP1 := TIdSMTP.Create(nil);
try
idSMTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(idSMTP1);
idSMTP1.UseTLS := utUseExplicitTLS;
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvSSLv3;
idSMTP1.Host := 'smtp.office365.com';
idSMTP1.Port := 587;
idSASLLogin := TIdSASLLogin.Create(idSMTP1);
idUserPassProvider := TIdUserPassProvider.Create(idSASLLogin);
idSASLLogin.UserPassProvider := idUserPassProvider;
idUserPassProvider.Username := ...;
idUserPassProvider.Password := ...;
idSMTP1.AuthType := satSASL;
idSMTP1.SASLMechanisms.Add.SASL := idSASLLogin;
try
idSMTP1.Connect;
try
idSMTP1.Authenticate;
finally
idSMTP1.Disconnect;
end;
ShowMessage('OK');
except
on E: Exception do
begin
ShowMessage(Format('Failed!'#13'[%s] %s', [E.ClassName, E.Message]));
raise;
end;
end;
finally
idSMTP1.Free;
end;
Update: Office365 no longer supports SSL v3, you must use TLS v1.x now:
(idSMTP1.IOHandler).SSLOptions.Method := sslvTLSv1;

Related

How do I solve [EIdSMTPReplyError] Authentication unsuccessful?

I'm trying to use SMTP with TLS and Office365. I'm able to successfully send an email using powershell and TLS but with the below example I'm currently stuck with error:
Project SMTP_SSL_Example.exe raised exception class EIdSMTPReplyError
with message 'Authentication unsuccessful
[JN2P275CA0026.ZAFP275.PROD.OUTLOOK.COM]'
The connection is successful but the authentication part in the code fails. I've previously been told that the response is coming from the server. If I get a successful mail using PowerShell how come this differs? Any ideas?
I'm using Indy 10.6.2.5366.
Update: I'm also getting the same kind of error with another component suit. I just don't understand why Powershell is allowing me to send the mail but I can't programmatically.
procedure TForm28.Method2Click(Sender: TObject);
var
idSMTP1: TIdSMTP;
idSASLLogin: TIdSASLLogin;
idUserPassProvider: TIdUserPassProvider;
begin
idSMTP1 := TIdSMTP.Create(nil);
try
idSMTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(idSMTP1);
idSMTP1.UseTLS := utUseExplicitTLS;
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvTLSv1;
idSMTP1.Host := 'smtp.office365.com';
idSMTP1.Port := StrToInt(cbPort.Text);
idSASLLogin := TIdSASLLogin.Create(idSMTP1);
idUserPassProvider := TIdUserPassProvider.Create(idSASLLogin);
idSASLLogin.UserPassProvider := idUserPassProvider;
idUserPassProvider.Username := 'my username';
idUserPassProvider.Password := 'my passowrd';
idSMTP1.AuthType := satSASL;
idSMTP1.SASLMechanisms.Add.SASL := idSASLLogin;
try
idSMTP1.Connect;
try
idSMTP1.Authenticate;
SendEmail(idSMTP1);
finally
idSMTP1.Disconnect;
end;
ShowMessage('OK');
except
on E: Exception do
begin
ShowMessage(Format('Failed!'#13'[%s] %s', [E.ClassName, E.Message]));
raise;
end;
end;
finally
idSMTP1.Free;
end;
end;
procedure TForm28.Mehod1Click(Sender: TObject);
var
idSMTP1: TIdSMTP;
begin
idSMTP1 := TIdSMTP.Create(nil);
try
idSMTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(idSMTP1);
idSMTP1.UseTLS := utUseExplicitTLS;
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvTLSv1;
idSMTP1.Host := 'smtp.office365.com';
idSMTP1.Port := StrToInt(cbPort.Text);
idSMTP1.AuthType := satDefault;
idSMTP1.Username := 'my username';
idSMTP1.Password := 'my password';
try
idSMTP1.Connect;
try
idSMTP1.Authenticate;
SendEmail(idSMTP1);
finally
idSMTP1.Disconnect;
end;
ShowMessage('OK');
except
on E: Exception do
begin
ShowMessage(Format('Failed!'#13'[%s] %s', [E.ClassName, E.Message]));
raise;
end;
end;
finally
idSMTP1.Free;
end;
end;
Office 365 will soon require TLS 1.2, but your code is forcing Indy to use TLS 1.0 instead. Office 365 officially does not support TLS 1.0 or 1.1 anymore, but it still accepts 1.0/1.1 sessions for the time being, but that will change in the coming months.
So, at the very least, you need to change this:
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvTLSv1;
To this:
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvTLSv1_2;
Or better, to this:
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
That being said, using TIdSASLLogin as the sole SASL mechanism is exactly the same as using TIdSMTP.AuthType=satDefault. They both send the same AUTH LOGIN command to the server. And that command is what is failing. But there is no way to know for sure exactly why that is happening. "Authentication unsuccessful" is too generic an error message, and there are many reasons why that error occurs in Office 365. Maybe you are using the wrong username/password. Maybe the IP address resolved from the hostname being sent by TIdSMTP in its EHLO command 1 is not whitelisted on the server. Who knows.
1: try setting the TIdSMTP.HeloName property to a FQDN for your client machine, which you can get from GetComputerNameEx().

TIdhttp HTTPS handshake Failed

I am using Indy 10 to connect to a SOAP Web Service. When I run the code with Fiddler running I find the webserver is not negotiating our Handshake. I have attached a screen shot of the Fiddler Inspectors.
We have been able to successfully connect to the server using the shareware application "SoapUI". I have attached a screen shot of the inspectors when using SoapUI.
One thing I notice is SoapUI is using a different version of SSL/TLS. How do I configure Indy to use the same version?
Any other insight as to why my call is failing?
procedure TForm6.Button1Click(Sender: TObject);
var
idhttp: TIdhttp;
IdSSLIOHandlerSocket1 : TIdSSLIOHandlerSocketOpenSSL;
Params : TStringStream;
begin
idhttp := TIdhttp.Create(nil);
IdSSLIOHandlerSocket1 := TIdSSLIOHandlerSocketOpenSSL.create(nil);
idhttp.ProxyParams.ProxyServer := '127.0.0.1';
idhttp.ProxyParams.ProxyPort := 8888 ;
idhttp.Request.ContentType := 'text/xml';
idhttp.Request.CharSet:='utf-8';
idhttp.request.connection := 'keep-alive';
idhttp.Request.CustomHeaders.AddValue('Content-Type','text/xml;charset=UTF-8');
idhttp.Request.CustomHeaders.AddValue('SOAPAction','"http://ws.nemsis.org/SubmitData"');
idhttp.Request.CustomHeaders.AddValue('Host','nemsis.org:443');
idhttp.Request.BasicAuthentication := True;
idhttp.request.username := 'xxxxx';
idhttp.request.password := 'yyyyy';
with IdSSLIOHandlerSocket1 do begin
SSLOptions.Method := sslvTLSv1_2;
SSLOptions.SSLVersions := [sslvTLSv1_2];
SSLOptions.VerifyMode := [];
SSLOptions.VerifyDepth := 2;
end;
with IdHTTP do begin
IOHandler := IdSSLIOHandlerSocket1;
end;
Params := TStringStream.Create(filetostring(ExtractFileDir(ParamStr(0))+'\sample.xml'));
idhttp.Post('https://nemsis.org:443/NemsisV3Validator4/NemsisWsService',Params);
end;
Failed Call:
Successful Call using SoapUI:

Send email using indy component delphi xe2 SSL negotiation faild

I tried with Indy component to send email in XE2, and it works fine on my laptop that I compiled my project on.
But if I take my exe project to another PC, it shows an error message
Connection closed gracefully
or, sometimes I get
SSL Negotiation failed
Actually I tried many times to solve my problem, but I can't.
This is my code - where is my mistake? I need a practical solution.
procedure Gmail(username, password, totarget, subject, body :string);
var
DATA : TIdMessage;
SMTP : TIdSMTP;
SSL : TIdSSLIOHandlerSocketOpenSSL;
result:Boolean;
begin
try
SMTP := TIdSMTP.Create(nil);
DATA := TIdMessage.Create(nil);
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
SSL.Destination := 'smtp.gmail.com:587';
SSL.Host := 'smtp.gmail.com';
// SSL.MaxLineAction.maException;
SSL.Port:= 587;
SSL.SSLOptions.Method := sslvTLSv1;
SSL.SSLOptions.Mode := sslmUnassigned;
SSL.SSLOptions.VerifyMode := [];
SSL.SSLOptions.VerifyDepth := 0;
DATA.From.Address := username;
DATA.Recipients.EMailAddresses := totarget;
DATA.Subject := subject;
DATA.Body.Text := body;
if FileExists('D:\Test1.txt') then
TIdAttachmentFile.Create(DATA.MessageParts, 'D:\Test1.txt');
SMTP.IOHandler := SSL;
SMTP.Host := 'smtp.live.com';
SMTP.Port := 587 ;
SMTP.Username := username;
SMTP.Password := password;
// SMTP.SASLMechanisms;
SMTP.UseTLS := utUseExplicitTLS;
try
try
SMTP.Connect;
SMTP.Send(DATA);
Result := True;
except
on E:Exception do
begin
ShowMessage('Cannot send E-Mail: ' + E.Message);
Result := False;
end;
end;
finally
if SMTP.Connected then SMTP.Disconnect;
end;
except
on E : Exception do
begin
ShowMessage('Error in the function SendEmailDelphi: ' + E.Message);
Result := False;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Timer1.Enabled:= True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
mail_username := 'email#gmail.com';
mail_password := 'pass';
mail_to := 'email#gmail.com';
mail_subject := 'Text email from Delphi project';
mail_body := 'this is a test email sent from Delphi project, do not reply';
try
begin
Gmail(mail_username, mail_password, mail_to , mail_subject, mail_body);
end;
finally
end;
end;
DO NOT set the SSL.Destination, SSL.Host, or SSL.Port properties manually! TIdTCPClient.Connect() handles that for you. Besides, don't you think it's odd that you are setting SSL.Destination/Host to smtp.gmail.com but are setting SMTP.Host to smtp.live.com instead? Gmail and Live are not the same service provider.
Also, SSL.SSLOptions.Mode should be set to sslmClient instead of sslmUnassigned. Not too important, TIdSSLIOHandlerSocketOpenSSL will simply flip it when it configures the connection. But you should do it anyway, since you know your code is acting as a client.
And lastly, try setting SMTP.UseTLS before setting SMTP.Port, as setting UseTLS may change the Port, so you want to make sure you are really connecting to the correct port you are expecting.
With that said, the SSL Negotiation failed error means the TLS handshake was started but failed part-way through the negotiation. Try assigning handlers to TIdSSLIOHandlerSocketOpenSSL's OnStatusInfo/Ex events to see how far the handshake is actually getting. And if you are using a relatively modern version of Indy 10, try looking at the raised exception's InnerException property, it might give you a clue as to what went wrong before the EIdTLSClientTLSHandShakeFailed exception was raised afterwards.

Sending mail using Indy and smtp

Im trying to send mail using this code:
With IdMessage1 Do Begin
Recipients.EMailAddresses := 'XXXXX#gmail.com';
From.Address := 'XXXXX#gmail.com';
From.Name := edit_from.Text;
CCList.EMailAddresses := '';
BccList.EMailAddresses := '';
Priority := mpNormal;
Subject := edit_subject.Text;
Body.Add(memo_body.Lines.Text);
End;
With IdSMTP1 Do Begin
Host := 'smtp.gmail.com';
Username := 'XXXXX#gmail.com';
Password := '*****';
IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
Port := 465;
UseTLS := utUseImplicitTLS;
Try
Connect;
Except
End;
If Not Connected Then Begin
Showmessage('Error');
Exit;
End;
Try
Send(IdMessage1);
Finally
Disconnect;
End;
End;
It works fine on my computer but when i test it on other machines the 'ERROR' (Error in If block before last Try block) will be raised...
Where is the problem?
This is not the proper way to do error handling with Indy. It should be more like this instead:
With IdSMTP1 Do Begin
IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
UseTLS := utUseImplicitTLS;
Host := 'smtp.gmail.com';
Username := 'XXXXX#gmail.com';
Password := '*****';
Port := 465;
Try
Connect;
Try
Send(IdMessage1);
Finally
Disconnect;
End;
Except
Showmessage('Error');
Exit;
End;
End;
Send() and Disconnect() can fail just as easily as Connect() can. If you want Connect() to be in its own try/except block, then at least don't use Connected to validate whether Connect() succeeded:
Try
Connect;
Except
Showmessage('Error connecting');
Exit;
End;
Try
Try
Send(IdMessage1);
Finally
Disconnect;
End;
Except
Showmessage('Error sending');
Exit;
End;
That being said, the exception tells you what actually failed, so do not ignore it. Had you displayed its content, you would have had a better idea of what was failing, eg:
Except
on E: Exception do
Begin
ShowMessage(Format('Error!'#10'[%s] %s', [E.ClassName, e.Message]));
Exit;
End;
End;
The most likely culprit is that you did not deploy the OpenSSL DLLs with your app. You can download them from OpenSSL's website, or from Indy's Fulgan mirror.

Delphi Indy 10 Smtp Error "Unable to authenticate at present"

I am using this piece of code to mail a test message from delphi indy.
I have a TidSMTP,TIdMessage and IdSSLIOHandlerSocketOpenSSL;
In the belowe code if i set it up to use gmail with ssl it works fine, but as soon as i replace my the server details with my cpanel mail server detials it does not work error:
" unable to authenticate at present".
I used same details I would use to setup my account in outlook 2007. Here is the code
IdSSLIOHandlerSocketOpenSSL details.
method := sslvsslv3
mode := sslmUnassigned
//rest default values
procedure Tfrmnotification.btnSendClick(Sender: TObject);
var
IdMsg : TIdMessage;
begin
begin
IdMsg := TIdMessage.Create(nil);
try
with TIdSMTP.Create(nil) do
try
// UserName := 'something#gmail.com';
// Password := 'pass';
// Host := 'smtp.gmail.com';
// IOHandler := IdSSLIOHandlerSocketOpenSSL;
// Port := 587;
UserName := 'something#sasra.co.za';
Password := 'password';
Host := 'outgoing server detials';// same as outlooks
IOHandler := IdSSLIOHandlerSocketOpenSSL;
Port := 465;// this is correct port
UseTLS:= utUseExplicitTLS;
IdMsg.Body.Add('test');
IdMsg.Recipients.emailAddresses := 'something#gmail.com';
IdMsg.Subject := 'test';
IdMsg.From.Address := 'something#sasra.co.za';
IdMsg.From.Name := 'john';
Connect;
Send(IdMsg);
Disconnect;
finally
Free;
end;
finally
IdMsg.free;
end;
showmessage('done');
end;
Any help would be appricated.
Port 465 is used for SMTP over implicit SSL. You have set UseTLS to utUseExplicitTLS. The correct value should (most likely) be utUseImplicitTLS.

Resources