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.
Related
This is a follow up question to Using INDY 10 SMTP with Office365 and Cannot use secure SMTP connection to Office365 with Delphi 2010 and Indy 10.5.5.
I have the following routine, incorporating points made in both threads (specifically, I set IdSMTP.AuthType := satSASL, provide the most common SASL mechanisms for TIdSMTP to choose from and I use Explicit TLS and sslvTLSv1):
procedure TEmailAlertSuite.AddSslHandler(const Username, Password: string);
var
SASLAnonymous: TIdSASLAnonymous;
SASLDigest: TIdSASLDigest;
SASLLogin: TIdSASLLogin;
SASLOTP: TIdSASLOTP;
SASLMD5: TIdSASLCRAMMD5;
SASLPlain: TIdSASLPlain;
SASLSHA1: TIdSASLCRAMSHA1;
SASLSkey: TIdSASLSKey;
UserPassProvider: TIdUserPassProvider;
begin
FSmtp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(FSmtp);
TIdSSLIOHandlerSocketOpenSSL(FSmtp.IOHandler).SSLOptions.Method := sslvTLSv1;
FSmtp.UseTLS := utUseExplicitTLS;
// When we explicitly assign the port, we just get connection timeouts...
// FSmtp.Port := 587;
// This needs to be true, so that TIdSMTP can decide which SASL to use,
// from the ones provided below.
// (https://stackoverflow.com/questions/17734414/using-indy-10-smtp-with-office365)
FSmtp.UseEhlo := True;
FSmtp.Username := Username;
FSmtp.Password := Password;
FSmtp.AuthType := satSASL;
UserPassProvider := TIdUserPassProvider.Create;
UserPassProvider.Username := Username;
UserPassProvider.Password := Password;
// SASL mechanisms are declared and added in descending order of security
// (as far as that can be known -- not all units give a value for FSecurityLevel).
SASLOTP := TIdSASLOTP.Create(FSmtp);
SASLOTP.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLOTP;
SASLSkey := TIdSASLSKey.Create(FSmtp);
SASLSkey.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLSKey;
SASLSHA1 := TIdSASLCRAMSHA1.Create(FSmtp);
SASLSHA1.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLSHA1;
SASLMD5 := TIdSASLCRAMMD5.Create(FSmtp);
SASLMD5.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLMD5;
SASLLogin := TIdSASLLogin.Create(FSmtp);
SASLLogin.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLLogin;
SASLDigest := TIdSASLDigest.Create(FSmtp);
SASLDigest.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLDigest;
SASLPlain := TIdSASLPlain.Create(FSmtp);
SASLPlain.UserPassProvider := UserPassProvider;
FSmtp.SASLMechanisms.Add.SASL := SASLPlain;
// (least secure)
SASLAnonymous := TIdSASLAnonymous.Create(FSmtp);
FSmtp.SASLMechanisms.Add.SASL := SASLAnonymous;
FSmtp.ValidateAuthLoginCapability := False;
end;
I set FSmtp.ValidateAuthLoginCapability := False; and FSmtp.UseEhlo := True;, so that TIdSMTP would decide for itself which SASL mechanism to use.
Notice, too, that I had to comment out the explicit assignment of the port. This is because we would get a socket timeout, when assigning it. This is despite following the advice in Send email using indy component delphi xe2 SSL negotiation faild, and making the assignment after setting UseTLS to utUseExplicitTLS.
When I run this on my O365 tenant, I get the following log output, which shows the capabilities of the tenant and an exception:
FSmtp.Capabilities:
SIZE 157286400
PIPELINING
DSN
ENHANCEDSTATUSCODES
STARTTLS
8BITMIME
BINARYMIME
CHUNKING
SMTPUTF8
2020-06-02 10:12:46.232 - Doesn't support AUTH or the specified SASL handlers!!
Notice there is no announced value for AUTH.
I'm not sure what to try next. At this point, I expected TIdSMTP to be able to determine the correct mechanism to use and to successfully connect and send email. Any thoughts?
Thanks!
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 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.
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;
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;