我正在尝试使用Delphi帮助,Indy示例和Google开发SMTP中继服务器。
我刚刚开始并有一个虚拟SMTP客户端,它将测试消息发送到SMTP服务器,稍后将对其进行处理并使用SMTP中继转发它。
在服务器上,我为每位收件人收到一个OnRcpt
(我使用一个To
,一个CC
和一个Bcc
进行测试。
当我处理To
并将CC
转换为AMsg
时,我也会在OnMsgReceive
中看到AMsg
和TStringStream
收件人(适当地加前缀)使用To:
和CC:
),但我看不到BCC
。
问题:如何判断哪些地址为To
,CC
和BCC
?
这是一些非常简单的代码。我正在设置断点&检查收到的参数,试图看看是什么东西
procedure TEmailMonitorMainForm.IdSMTPServerMsgReceive(ASender: TIdSMTPServerContext;
AMsg: TStream; var VAction: TIdDataReply);
var
LMsg : TIdMessage;
begin
LMsg := TIdMessage.Create(Nil);
LMsg.LoadFromStream(AMsg);
LMsg.Free(); // breakpoint here examine Lmsg
end; // IdSMTPServerMsgReceive()
[更新]当我发送,然后<message>.BCCList.Count = 1
,但是当我收到时,它是0,而收到的CClist.Count
是1,应该是。
答案 0 :(得分:3)
在服务器上,我为每个收件人收到一个OnRcpt(我用一个To,一个CC和一个Bcc进行测试)。
SMTP协议不区分To
,CC
和BCC
收件人。这是电子邮件格式的工件,通过其To:
和Cc:
标头(没有Bcc:
标头,但TIdMessage.SaveToFile()
创建了一个,因此TIdMessage.LoadFromFile()
可以重新设置加载它)。当SMTP客户端向SMTP服务器发送电子邮件时,客户端会确定目标收件人并在服务器的单独RCPT TO
命令中指定每个收件人(这是允许BCC
工作的 - 但没有电子邮件本身中的Bcc:
标头,但服务器为每个RCPT TO
收件人提供了Bcc
命令。 RCPT TO
地址是TIdSMTPServer.OnRcptTo
事件中指定的值,并在TIdSMTPServerContext.RCPTList
属性中收集。这些地址由SMTP客户端明确请求,并且是您应该将电子邮件发送到的唯一地址(而不是电子邮件标头中指定的收件人)。
当我处理OnMsgReceive并将AMsg转换为TStringStream(适当地以To:和CC :)作为前缀时,我也看到AMsg中的To和CC收件人,但我没有看到BCC那里。
就SMTP服务器而言,实际的电子邮件本身只是任意数据。它旨在按原样交付给每个请求的收件人。这就是为什么电子邮件数据在TStream
事件中以TIdSMTPServer.OnMsgReceive
的形式提供的原因,以及为什么Indy 10中的TIdSMTPServer
不会像在Indy中那样提供基于TIdMessage
的事件9及更早。
如果电子邮件采用RFC 822/2822/5322格式(通常是这种格式),则会有To:
和Cc:
个标头。接收/加载此类电子邮件到TIdMessage
时,这些标头分别用于填写TIdMessage.Recipients
和TIdMessage.CCList
属性。但由于通常没有Bcc:
标题(除非从TIdMessage.SaveToFile()
创建的文件加载电子邮件),TIdMessage.BCCList
将不会被填写。
如何判断哪些地址是To,CC和BCC?
由于SMTP协议本身不区分不同的收件人类型,因此区分它们的唯一方法是解析电子邮件,查看其To:
和Cc:
标头。 TIdSMTPServerContext.RCPTList
属性中不属于这两个标头之一的任何地址都必须是Bcc
收件人。但是,无法保证TIdSMTPServerContext.RCPTList
属性中的其他地址始终与To:
和Cc:
标头匹配(尽管它们通常会匹配),因为从技术上讲,SMTP客户端可以发送任何原始它想要的数据和SMTP将按原样提供它,而不关心它实际包含的内容。
这里有一些非常简单的代码。
请勿使用TIdMessage.LoadFromStream()
来解析TStream
事件提供的TIdSMTPServer.OnMsgReceive
对象!它并不总是正常工作。在Embarcadero和AToZed论坛中已经多次详细讨论了技术原因,例如this discussion。您需要暂时使用以下解决方法。这个问题将在Indy 11中解决:
procedure TEmailMonitorMainForm.IdSMTPServerMsgReceive(ASender: TIdSMTPServerContext; AMsg: TStream; var VAction: TIdDataReply);
var
LMsg : TIdMessage;
LClient: TIdMessageClient;
LIO: TIdIOHandlerStreamMsg;
begin
LMsg := TIdMessage.Create(Nil);
try
//LMsg.LoadFromStream(AMsg);
LClient := TIdMessageClient.Create;
try
LIO := TIdIOHandlerStreamMsg.Create(LClient, AMsg);
LIO.FreeStreams := False;
LIO.EscapeLines := True;
LIO.Open;
LClient.IOHandler := LIO;
LClient.ProcessMessage(LMsg, False);
finally
LClient.Free;
end;
// now you can use LMsg as needed...
finally
LMsg.Free;
end;
end;