Reputation: 608
I'm having a very strange problem sending emails via indy through two different mechanisms in my program. This problem is similar to [this one][1], but not exactly the same. I'm using Indy 10.5 with the latest OpenSSL libraries and Delphi XE3.
The first code snippet, which works, is a simple SMTP client I wrote. Here's an example of how I set it up. This isn't the exact code but it should give you an idea.
FIndySMTP.Intercept := FIndyLogFile;
FIndySMTP.IOHandler := FIndySSLHandler;
FIndyMessage.From.Address := FEmailAddress;
FIndySSLHandler.Destination := FSMTPAddress + ':' + IntToStr(FSMTPPort);
FIndySSLHandler.Host := FSMTPAddress;
FIndySSLHandler.Port := FSMTPPort;
FIndySMTP.Host := FSMTPAddress;
FIndySMTP.Port := FSMTPPort;
FIndySMTP.Username := FAccountName;
FIndySMTP.Password := FAccountPass;
FIndySMTP.AuthType := satDefault;
FIndySMTP.UseEhlo := True;
FIndySMTP.UseTLS := utUseExplicitTLS
FIndySMTP.Connect;
try
if FIndySMTP.Connected = True then
FIndySMTP.Send(FIndyMessage);
finally
FIndySMTP.Disconnect;
end;
This generates a successful email with the log:
Recv 10/9/2015 10:41:02 AM: 220 server.server1.local Microsoft ESMTP MAIL Service ready at Fri, 9 Oct 2015 13:41:01 -0400<EOL>
Sent 10/9/2015 10:41:02 AM: EHLO DEIMOS<EOL>
Recv 10/9/2015 10:41:02 AM: 250-server.server1.local Hello [68.14.239.173]<EOL>250-SIZE 36700160<EOL>250-PIPELINING<EOL>250-DSN<EOL>250-ENHANCEDSTATUSCODES<EOL>250-AUTH<EOL>250-8BITMIME<EOL>250-BINARYMIME<EOL>250 CHUNKING<EOL>
Sent 10/9/2015 10:41:02 AM: RSET<EOL>
Recv 10/9/2015 10:41:02 AM: 250 2.0.0 Resetting<EOL>
....(The rest snipped)
Now the second method, which uses Report Builder built in Email components to send a Report via email (again, some code is snipped for brevity, the real clue is in the logs):
lIOHandler.Destination := Host + ':' + IntToStr(Port);
lIOHandler.Host := Host;
lIOHandler.Port := Port;
TheReport.EmailSettings.HostAddress := Host;
TheReport.EmailSettings.UserName := UserName;
TheReport.EmailSettings.Password := Password;
lEmail.SMTP.OnEmailError := FMain.EmailErrorEvent;
TppSMTPIndy(lEmail.SMTP).IndySMTP.OnFailedRecipient := FMain.idSMTPFailedRecipient;
TppSMTPIndy(lEmail.SMTP).IndySMTP.Intercept := FMain.IdLogFile1;
TppSMTPIndy(lEmail.SMTP).IndySMTP.Port := Port;
TppSMTPIndy(lEmail.SMTP).IndySMTP.IOHandler := lIOHandler;
TppSMTPIndy(lEmail.SMTP).IndySMTP.UseTLS := utUseExplicitTLS;
TppSMTPIndy(lEmail.SMTP).IndySMTP.AuthType := satDefault;
TppSMTPIndy(lEmail.SMTP).IndySMTP.UseEhlo := True;
TheReport.SendMail;
You can see that with the exception of using the Report Builder TppSMTPIndy, every setting is the same. Yet the email does not get sent, and the log looks like this:
Stat Connected.
Recv 10/9/2015 10:44:31 AM: 220 server.server1.local Microsoft ESMTP MAIL Service ready at Fri, 9 Oct 2015 13:44:28 -0400<EOL>
Sent 10/9/2015 10:44:31 AM: EHLO DEIMOS<EOL>
Recv 10/9/2015 10:44:31 AM: 250-server.server1.local Hello [68.14.239.173]<EOL>250-SIZE 36700160<EOL>250-PIPELINING<EOL>250-DSN<EOL>250-ENHANCEDSTATUSCODES<EOL>250-AUTH<EOL>250-8BITMIME<EOL>250-BINARYMIME<EOL>250 CHUNKING<EOL>
Sent 10/9/2015 10:44:31 AM: QUIT<EOL>
Recv 10/9/2015 10:44:31 AM: 221 2.0.0 Service closing transmission channel<EOL>
Stat Disconnected.
You can see that a QUIT is sent immediately after receiving HELLO. This is why my question is different than the link above. That person was at least receiving a STARTTLS request.
What could be causing Indy to send a QUIT immediately after receiving a HELLO? I am not getting any errors. It just silently fails and the program moves on.
Now here's a kicker hint. If I set the AuthType to satNone in the Report Builder example it works. While in my first example I can set the AuthType to satNone and satDefault and both work.
Any ideas?
Thanks a lot for your time.
Upvotes: 0
Views: 2695
Reputation: 595732
What could be causing Indy to send a QUIT immediately after receiving a HELLO?
The only time QUIT
is sent is when TIdSMTP.Disconnect()
is called.
The only times that TIdSMTP
itself calls Disconnect()
are when:
an exception is raised inside of TIdSMTP.Connect()
, such as if the server's greeting has an error code, or there is a unexpected problem parsing the server's greeting or EHLO
response.
an exception is raised inside of TIdSMTP.StartTLS()
, which is called by TIdSMTP.Authenticate()
(which is called by TIdSMTP.Send()
if not already called beforehand). However, since you have set UseTLS=utUseExplicitTLS
and the server's EHLO
response does not advertise support for STARTTLS
, TIdSMTP.StartTLS()
is effectively a no-op on this server.
I am not getting any errors. It just silently fails and the program moves on.
Unless Report Builder is catching exceptions internally and not passing them into your code, then the most likely scenario is that Report Builder itself is calling TIdSMTP.Disconnect()
without calling TIdSMTP.Send()
first. The RSET
command shown in your log is sent by TIdSMTP.Send()
at the beginning of the email (BTW, more recent versions of Indy no longer send RSET
unless the email fails with an SMTP error code). Report Builder is likely just skipping Send()
, and I can think of one possible reason why it might do that.
AuthType=satDefault
uses the AUTH LOGIN
command (which is not a secure command), but your server's EHLO
response is not advertising support for LOGIN
authentication (in fact, it is not advertising support for any authentications at all). As such, TIdSMTP.Authenticate()
will skip authentication on this server by default and return False, and also set the TIdSMTP.DidAuthenticate
property to False. Maybe Report Builder is calling TIdSMTP.Authenticate()
directly and checking the result before calling TIdSMTP.Send()
. Your non-ReportBuilder example does not do that validation. Setting AuthType=satNone
will cause TIdSMTP.Authenticate()
to return True and set the TIdSMTP.DidAuthenticate
property to True.
If the server happens to support LOGIN
authentication (some servers do support it without advertising it), you can set the TIdSMTP.ValidateAuthLoginCapability
property to False (it is True by default) to make satDefault
attempt authentication as long as the TIdSMTP.Username
property has been assigned a non-blank string.
Upvotes: 3