我在我的程序中通过两种不同的机制通过indy发送电子邮件时遇到了一个非常奇怪的问题。这个问题类似于[这一个] [1],但不完全相同。我正在使用Indy 10.5和最新的OpenSSL库和Delphi XE3。
第一个有效的代码片段是我写的一个简单的SMTP客户端。这是我如何设置它的一个例子。这不是确切的代码,但它应该给你一个想法。
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;
这会生成包含日志的成功电子邮件:
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)
现在是第二种方法,它使用内置电子邮件组件的报表生成器通过电子邮件发送报表(同样,为简洁起见,一些代码被剪断,真正的线索在日志中):
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;
您可以看到,除了使用Report Builder TppSMTPIndy之外,每个设置都是相同的。然而,电子邮件没有被发送,日志看起来像这样:
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.
您可以看到在收到HELLO后立即发送QUIT。这就是我的问题与上面的链接不同的原因。该人至少收到了STARTTLS请求。
什么可能导致Indy在收到HELLO后立即发送退出?我没有收到任何错误。它只是默默地失败,程序继续前进。
现在这里有一个踢球提示。如果我在报表生成器示例中将AuthType设置为satNone,则它可以正常工作。在我的第一个例子中,我可以将AuthType设置为satNone和satDefault,两者都有效。
有什么想法吗?
非常感谢你的时间。
答案 0 :(得分:3)
什么可能导致Indy在收到HELLO后立即发送退出?
发送QUIT
的唯一时间是TIdSMTP.Disconnect()
被调用。
TIdSMTP
本身调用Disconnect()
的唯一时间是:
在TIdSMTP.Connect()
内引发异常,例如,如果服务器的问候语有错误代码,或解析服务器的问候语或EHLO
响应时出现意外问题。
TIdSMTP.StartTLS()
内部引发异常,由TIdSMTP.Authenticate()
调用(如果事先未调用,则由TIdSMTP.Send()
调用)。但是,由于您设置了UseTLS=utUseExplicitTLS
且服务器的EHLO
响应未宣传对STARTTLS
的支持,因此TIdSMTP.StartTLS()
实际上是此服务器上的无操作。
我没有收到任何错误。它只是默默地失败,程序继续前进。
除非Report Builder在内部捕获异常而不将其传递到您的代码中,否则最有可能的情况是Report Builder本身正在调用TIdSMTP.Disconnect()
而不先调用TIdSMTP.Send()
。日志中显示的RSET
命令由TIdSMTP.Send()
在电子邮件开头发送(BTW,更新版本的Indy不再发送RSET
,除非电子邮件失败,并显示SMTP错误代码)。报表生成器可能只是跳过Send()
,我可以想到它可能会这样做的一个可能原因。
AuthType=satDefault
使用AUTH LOGIN
命令(这不是安全命令),但您服务器的EHLO
响应并未宣传对LOGIN
身份验证的支持(事实上,它并非广告支持任何身份验证。因此,TIdSMTP.Authenticate()
将默认跳过此服务器上的身份验证并返回False,并将TIdSMTP.DidAuthenticate
属性设置为False。也许Report Builder直接调用TIdSMTP.Authenticate()
并在调用TIdSMTP.Send()
之前检查结果。您的非ReportBuilder示例不执行该验证。设置AuthType=satNone
会导致TIdSMTP.Authenticate()
返回True并将TIdSMTP.DidAuthenticate
属性设置为True。
如果服务器恰好支持LOGIN
身份验证(某些服务器支持它而不通告它),您可以将TIdSMTP.ValidateAuthLoginCapability
属性设置为False(它是True默认)只要satDefault
属性被分配了非空字符串,就TIdSMTP.Username
尝试进行身份验证。