This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Delphi + Indy: Connection closed gracefully
I want to send some E-mails with delphi, i had this little code :
procedure TForm1.Button1Click(Sender: TObject);
var i : integer;
begin
IdMsgSend := TIdMessage.Create(nil);
SSLHandler :=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
with IdMsgSend do
begin
ContentType := 'text/plain';
Body.Text := 'Test test text';
From.Text := 'USERNAME#gmail.com';
ReplyTo.EMailAddresses := 'Recipient#server.com';
Recipients.EMailAddresses := 'Recipient#server.com';
Subject := 'i just came to say hello';
end;
SMTP := TIdSMTP.Create(nil);
try
SMTP.Username := 'USERNAME#gmail.com';
SMTP.Password := 'PASSWODD';
SMTP.Host := 'smtp.gmail.com';
SMTP.Port := 465;
SMTP.IOHandler := SSLHandler;
SSLHandler.SSLOptions.Method := sslvSSLv3;
SMTP.UseTLS := utUseExplicitTLS;
SMTP.Connect;
try
IdMsgSend.Body.Text := 'The body';
IdMsgSend.Subject := 'The subject';
SMTP.Send(IdMsgSend);
finally
SMTP.Disconnect;
end;
finally
FreeAndNil(SMTP);
end;
finally
FreeAndNil(IdMsgSend);
end;
end;
It used to work just fine! now, everytime i try to send an email i get this error at the SMTP.Send(IdMsgSend) :
Connection closed Gracefully
I've read that it might be from the antivirus or firewall, so i disabled them both, but still same problem?
What is wrong here? did gmail changed its SMTP options or something like that?
According to this article, it's an exception that's not correctly handled by Delphi. Try to do the shown modification on your Debugger Options and the problem will be solved.
Related
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().
I tried using TRESTClient to connect to an HTTPS web service using TLS 1.2. But NO LUCK with sending multipart/form-data.
So now I am trying with Indy. I got this "Wrong Version Number" error.
I think there is nothing wrong with the code since it worked with HTTP.
Probably my Delphi is missing something. What should I install and how?
procedure TForm10.Button2Click(Sender: TObject);
var
HTTP: TIdHTTP;
RequestBody: TStream;
ResponseBody: string;
myssl: TIdSSLIOHandlerSocketOpenSSL;
Input: TIdMultipartFormDataStream;
begin
ResponseBody := '';
try
try
HTTP := TIdHTTP.Create;
try
Input := TIdMultipartFormDataStream.Create;
try
Input.Clear;
Input.AddFormField('Email', 'xx#xx.com.tr');
Input.AddFormField('Password', 'xx');
myssl := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
HTTP.IOHandler := myssl;
myssl.SSLOptions.Mode := sslmUnassigned;
myssl.SSLOptions.Method := sslvTLSv1_2;
myssl.SSLOptions.SSLVersions := [sslvTLSv1_2];
HTTP.HTTPOptions := [hoForceEncodeParams];
HTTP.Request.CustomHeaders.FoldLines := False;
ResponseBody := HTTP.Post('https://xxx.com.tr/api/Mobile/MobileLoginControl', Input);
finally
Input.Free;
end;
finally
HTTP.Free;
end;
finally
end;
except
ResponseBody := '"-20"';
end;
end;
The code is fine, though you are enabling only TLS 1.2 on the SSLIOHandler. Maybe the website in question doesn't support TLS 1.2? Try enabling TLS 1.0 and 1.1 as well:
myssl.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
And don't set the SSLOptions.Method at all. Setting the SSLVersions updates the Method and vice versa. So set one or the other, not both.
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.
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.
Here is my Issue. I'm using Delphi 5 and Indy 9. I have no option to upgrade either at the moment. I am trying to send an email via gmail, and i hard code the string as 'smtp.google.com' it works just fine. however, if smtp.host is getting the host name from a variable it fails with error 11001, and i havent been able to figure out why. I'm new using indy so i'm probably missing something silly, but i don't understand why it could accept a string as the host, but not a variable holding the string. (It's got to be a variable because i need to pass the procedure different SMTP hosts based on the user signed in. Here is the code:
procedure TFormEmail.SendSimpleMail(ToEmail, MyAttachment: string);
var
Msg: TIdMessage;
DestAddr: TIdEmailAddressItem;
SMTP: TIdSMTP;
SSLHandler : TidSSLIOHandlerSocket;
Attachment: TIdAttachment;
SMTPHost1 :string;
begin
Msg := idMessage1;
Msg.From.Text := EmailName(My_User);
Msg.From.Address := EmailAddress(My_User);
msg.Subject := 'Test';//email subject
DestAddr := Msg.Recipients.Add;
DestAddr.Text := '';//receiver's name (optional)
DestAddr.Address := ToEmail;//where its going
Msg.Body.Add(edtEmailBody.text); //email body
SMTP := IdSMTP1;
SMTP.IOHandler := idSSLIOHandlerSocket1;
SMTPhost1 := SMTPHost(My_User);
SMTPhost1 := 'smtp.google.com';
//SMTP.Host := SMTPhost1; //<--FAILS
SMTP.Host := 'smtp.google.com'; //<--SUCCEEDS
SMTP.Port := SMTPPort(My_User);
SMTP.AuthenticationType := atLogin; //error here (2 error)
SMTP.Username := EmailAddress(My_User);
SMTP.Password := SMTPPassword(My_User);
If not empty(MyAttachment) then
Attachment := TIdAttachment.Create(Msg.MessageParts, MyAttachment);//loads Att
Try
SMTP.Connect;
except
SMTP.Connect;//refire if exception (issue with INDY)
end;
if useSSL(My_User) then
SMTP.SendCmd('STARTTLS');//load TLS
SMTP.Authenticate;
SMTP.Send(Msg);
SMTP.Disconnect;//disconnect from server
end;
I marked the one that fails and the one that succeeds, but i don't understand what i'm doing wrong. Any help would be appreciated
Seems you have more issues in one question, I can only help you with one.
I had the same issue with Connect, I simply called the Load method from IdSSLOpenSSLHeaders.
Try the following:
SMTP := IdSMTP1;
IdSSLOpenSSLHeaders.Load;
SMTP.IOHandler := idSSLIOHandlerSocket1;