【问题标题】:Indy SMTP server - how to detect CC & BCC recipients?Indy SMTP 服务器 - 如何检测 CC 和 BCC 收件人?
【发布时间】:2014-08-29 21:09:37
【问题描述】:

我正在尝试使用 Delphi 帮助、Indy 示例和 Google 开发一个 SMTP 中继服务器。

我刚刚开始,有一个虚拟 SMTP 客户端,它将测试消息发送到 SMTP 服务器,稍后将处理它并使用 SMTP 中继转发它。

在服务器上,我为每个收件人收到一个OnRcpt(我测试了一个To、一个CC 和一个Bcc)。

当我处理 OnMsgReceive 并将 AMsg 转换为 TStringStream (适当地以 To:CC: 为前缀)时,我还在 AMsg 中看到了 ToCC 收件人,但我那里看不到BCC

问题:我如何知道哪些地址是ToCCBCC


这里有一些非常简单的代码。我正在设置断点并检查接收到的参数以尝试查看发生了什么

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,应该是。

【问题讨论】:

    标签: delphi smtp indy10


    【解决方案1】:

    在服务器上,我为每个收件人收到一个 OnRcpt(我使用一个 To、一个 CC 和一个 Bcc 进行测试)。

    SMTP 协议不区分ToCCBCC 收件人。这是电子邮件格式通过其To:Cc: 标头(没有Bcc: 标头,尽管TIdMessage.SaveToFile() 创建一个因此TIdMessage.LoadFromFile() 可以重新加载它)的工件。当 SMTP 客户端向 SMTP 服务器发送电子邮件时,客户端会确定预期的收件人,并在单独的 RCPT TO 命令中指定每个收件人(这就是允许 BCC 工作的原因 - 没有 Bcc: 标头在电子邮件本身中,但为每个 Bcc 收件人提供了一个 RCPT TO 命令)。 RCPT TO 地址是在TIdSMTPServer.OnRcptTo 事件中指定的值,并收集在TIdSMTPServerContext.RCPTList 属性中。这些地址由 SMTP 客户端明确请求,并且是您应该将电子邮件发送到的唯一地址(不是电子邮件标头中指定的收件人)。

    当我处理 OnMsgReceive 并将 AMsg 转换为 TStringStream(适当地以 To: 和 CC: 为前缀)时,我还在 AMsg 中看到了 To 和 CC 收件人,但我在那里看不到 BCC。

    就 SMTP 服务器而言,实际的电子邮件本身只是任意数据。它旨在按原样交付给每个请求的收件人。这就是为什么电子邮件数据在 TIdSMTPServer.OnMsgReceive 事件中作为 TStream 提供,以及为什么 Indy 10 中的 TIdSMTPServer 不像在 Indy 9 和更早版本中那样提供基于 TIdMessage 的事件。

    如果电子邮件采用RFC 822/2822/5322 格式(通常是这样),它将具有To:Cc: 标头。当接收/加载此类电子邮件到TIdMessage 时,这些标题分别用于填写TIdMessage.RecipientsTIdMessage.CCList 属性。但是由于通常没有Bcc: 标头(除非电子邮件是从TIdMessage.SaveToFile() 创建的文件中加载的),所以TIdMessage.BCCList 不会被填写。

    我如何知道哪些地址是 To、CC 和 BCC?

    由于 SMTP 协议本身不区分不同的收件人类型,因此区分它们的唯一方法是解析电子邮件,查看其 To:Cc: 标头。 TIdSMTPServerContext.RCPTList 属性中不在这两个标头之一中的任何地址都必须是Bcc 收件人。但是,不能保证TIdSMTPServerContext.RCPTList 属性中的其他地址将始终与To:Cc: 标头匹配(尽管它们通常会匹配),因为从技术上讲,SMTP 客户端可以发送它想要的任何原始数据,而 SMTP将按原样交付,而不关心它实际包含的内容。

    这里有一些非常简单的代码。

    请勿使用TIdMessage.LoadFromStream() 解析TIdSMTPServer.OnMsgReceive 事件提供的TStream 对象!它不会总是正常工作。技术原因已在 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;
    

    【讨论】:

    • 哇,这里需要调整我的一些项目,不知道关于 OnMsgReceive...
    • @Remmy 一如既往地感谢您提供完整且内容丰富的答案。这应该对其他人非常有帮助。有关 Indy 11 到来的任何消息?任何关于 SMTP 服务器的推荐阅读材料,尤其是 Indy(除了易于使用的 Google 搜索)?
    猜你喜欢
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 2013-08-27
    • 2019-05-04
    相关资源
    最近更新 更多