我见过的所有Indy SMTP示例都显示TIdSMTP
在电子邮件发送例程开始时被实例化,并在结束时被释放。
我编写了一个基于Indy 10组件的SMTP电子邮件发件人原型应用程序,通常无问题。 (它可以通过明确或通过显式或隐式TLS发送。)它在启动时实例化TIdSMTP
并在关闭时释放它。
我刚遇到IdSMTP.Send
抛出异常,说SMTP没有连接的情况。这是不起眼的,除了我在IdSMTP.Connected
之前的IdSMTP.Send
测试报告SMTP已连接的事实。我的程序无法再发送电子邮件,因为它认为它已连接但实际上并非如此。唯一的解决方案是重启程序。当完成对这个原型应用程序的测试时,代码将被合并到一个服务器服务中,该服务不能只是重新启动来解决这类问题。
如果我在电子邮件发送程序中实例化了TIdSMTP
课程,那么问题本来可以避免,或者至少可以解决。在不太可能的重新发生的情况下,IdSMTP
对象将在过程结束时被释放,并在下次被调用时重新实例化。
我没有像示例中那样构建我的解决方案的原因是,为每个电子邮件发送重新实例化TIdSMTP
还要求IdSMTP
对象为每次发送重新连接到电子邮件服务器。这可能是一个非常缓慢的过程 - 外部电子邮件服务器的顺序为5到10秒 - 并且每次不重新实例化TIdSMTP
就可以避免这种开销。
所以我的问题是:这是(或类似的问题)所有示例每次都显示重新实例化的原因吗?或者,它只是展示一个完整的,包含的例子?后者是我如何解释它。
如果您对此问题的利弊有所了解,请提供您的意见和想法。
如果存在确定的最佳做法,那么听听也是有用的。
答案 0 :(得分:2)
我见过的所有Indy SMTP示例都显示TIdSMTP在电子邮件发送例程开始时被实例化,并在结束时被释放。
他们只是例子。显然,生产代码可能更复杂。您可以多次重复使用单个TIdSMTP
对象。
我在我的IdSMTP.Send之前测试了IdSMTP.Connected,它报告了SMTP已连接。
如果连接不可用,请Send()
失败并引发异常。 Indy使用异常进行错误报告,因此请使用它们,不要避免使用它们。 Connected()
可以报告误报。如果IOHandler.InputBuffer
中包含未读数据,Connected()
将返回true,即使底层套接字已关闭。这是设计的。不要依赖Connected()
来推动你的逻辑。
我的程序无法再发送电子邮件,因为它认为它已连接但实际上并非如此。
Connect()
成功后,如果您收到的任何异常都不是来自EIdRFCReply
,则应Disconnect()
建立连接,Clear()
InputBuffer
(如果在IOHandler
再次调用Disconnect()
之前,仍有Connect()
分配 - Connect()
将释放Connect()
内部Connected()
。如果 Try
If not SMTP.Connected then SMTP.Connect;
...
Except
On E: EIdRFCReply do
Begin
// an SMTP command failed, but the connection is still stable
...
End;
On E: Exception do
Begin
SMTP.Disconnect(False);
If SMTP.IOHandler <> nil then SMTP.IOHandler.InputBuffer.Clear;
...
End;
End;
返回true,则{{1}}会引发异常,因此如果发生意外错误,您必须手动清除导致该(未读数据)的条件。
{{1}}
答案 1 :(得分:1)
一般情况下,您应该尽可能短的时间保持与外界的联系。我假设这个程序/服务不会连续24小时/ 7天发送电子邮件,但是响应一些外部事件(计时器或其他事件触发“现在是时候发送”),然后发送一个(或更多) )那时的电子邮件。
我编写代码的方法是在此事件开始时实例化TIdSmtp,然后在结束时释放它。这样,每次都会有一个与外部实例化的新连接。
如果你的程序只在每个事件上发送一封电子邮件,那么你可以对它进行编码,这样如果发送失败,那么在下一个事件中发出信号,你应该重新实例化TIdSmtp变量,这些内容如下:
PROCEDURE SendMsg(...)
BEGIN
IF NOT Assigned(SMTP) THEN SMTP:=TIdSmtp.Create(NIL);
TRY
... Your code to send one or more emails ...
EXCEPT
FreeAndNIL(SMTP);
... Perhaps Re-Raise exception, if outer layer needs to know ...
END
END;
这样,SendMsg例程会在出错时自动重启。当然,更多的错误检查(捕获了什么样的异常)是可取的,但我希望你能得到一般的想法......