我想做什么? 使 SSL“隐式/显式”(对于 SMTP)配置透明,并且为了做到这一点,我显然是通过事件触发来做到这一点。
我的想法是捕获 SSL/TLS 协商成功或失败,然后使用其他选项重试。
我在
TIdSMTP
和TIdSSLIOHandlerSocketOpenSSL
上看到了一些事件,但它们似乎都没有触发正确性。
Indy 文档也无法在这里下载(DNS 损坏错误)。
我使用以下带有“
Sleep(1);
”的事件只是为了对它们进行断点。
:TIdSMTP
OnTLSNotAvailable
OnTLSHandShakeFailed
OnTLSNegCmdFailed
OnFailedEHLO
:TIdSSLIOHandlerSocketOpenSSL
OnStatus
OnStatusInfo
OnStatusInfoEx
我测试过的:
我使用 Outlook smtp.office365.com 和 587 端口(在 Indy 中为 STARTTLS -
utUseExplicitTLS
)作为示例,但我故意将 TIdSMTP.UseTLS
更改为 utUseImlicitTLS
以模拟 SSL/TLS 协商失败。
在第一个
TIdSMTP.Connect
中,我得到了 EIdSocketError
异常(“Socket Error # 10060 Connection timed out”),而不是 SSL/TLS 协商失败消息/异常。在本次测试中,唯一触发的事件是TIdSSLIOHandlerSocketOpenSSL.OnStatus
/TIdSMTP.OnStatus
。
在第二次
TIdSMTP.Connect
中,我没有收到带有超时消息的EIdSocketError
,除了第一次尝试时的事件之外,它还触发了TIdSSLIOHandlerSocketOpenSSL.OnStatusInfo
和TIdSSLIOHandlerSocketOpenSSL.OnStatusInfoEx
事件,处理SSL连接错误。
一些代码片段:
procedure Connect;
var
LSMTP: TIdSMTP;
LSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
LSMTP:= TIdSMTP.Create(nil);
LSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
{functions to be declared}
LSMTP.OnTLSNotAvailable := MyTLSNotAvailable;
LSMTP.OnTLSHandShakeFailed:= MyTLSHandShakeFailed;
LSMTP.OnTLSNegCmdFailed := MyTLSNegCmdFailed;
LSMTP.OnFailedEHLO := MyFailedEHLO;
LSSL.OnStatus := MyOnStatus;
LSSL.OnStatusInfo := MySSLInfo;
LSSL.OnStatusInfoEx:= MySSlInfoEx;
LSSL.ConnectTimeout:= 1000000;
LSSL.ReadTimeout := 1000000;
LSMTP.IOHandler := FSSL;
LSMTP.AuthType := satDefault;
LSMTP.UseTLS := utUseExplicitTLS;
LSSL.SSLOptions.Method:= sslvSSLv23;
LSSL.SSLOptions.Mode := sslmBoth;
LSMTP.Host:= 'smtp.office365.com';
LSMTP.Port:= '587';
LSMTP.Username:= [email protected];
LSMTP.Password:= password;
LSMTP.From:= LSMTP.Username;
try
LSMTP.Connect;
except
raise Exception.Create(Format('Error during connect attempt: %s',[Exception(ExceptObject).Message]));
end;
end;
所以,我有一些问题:
为什么
TIdSMTP.OnTLSNotAvailable
/TIdSMTP.OnTLSHandShakeFailed
/TIdSMTP.OnTLSNegCmdFailed
在这些情况下不会触发?
为什么
TIdSSLIOHandlerSocketOpenSSL.OnStatusInfo
和TIdSSLIOHandlerSocketOpenSSL.OnStatusInfoEx
仅在第二次连接尝试时触发?
我错过了什么?
如果您在显式 tls 端口上使用
utUseImplicitTLS
,客户端将在建立 TCP 连接后立即发送 TLS 握手,然后当它将服务器未加密的 SMTP 问候错误解释为 TLS 握手回复时,连接将会失败。
如果在隐式 TLS 端口上使用
utUseExplicitTLS
,客户端将在建立 TCP 连接后超时,因为它将等待服务器从不发送的未加密 SMTP 问候语,因为服务器正在等待 TLS 握手客户从不发送。