使用SMTP服务器发送BCC邮件?

19

我已经在我的一些代码中记录了这个问题:

/**
 * Add a BCC.
 *
 * Note that according to the conventions of the SMTP protocol all
 * addresses, including BCC addresses, are included in every email as it
 * is sent over the Internet. The BCC addresses are stripped off blind
 * copy email only at the destination email server.
 *
 * @param string $email
 * @param string $name
 * @return object Email
 */

我不记得从哪里获得它(可能的来源),但这与问题无关。基本上,每当我尝试通过SMTP发送带有BCC的电子邮件时,BCC地址都不会隐藏 - 我已经阅读了SMTP协议的整个RFC(几年前),我认为我没有遗漏任何内容。
奇怪的是,如果我使用内置的mail()函数发送带有BCC的电子邮件,一切都正常,我不知道为什么 - 我想自己编写电子邮件发送器,但我无法理解这一点。
请问有人能够阐明这个黑暗的主题吗?

1
我从未成功地完成过这项任务,除非是在重复使用同一连接的情况下发送单独的消息。即使你让密送(bcc)“起作用”(这取决于远程 MTA 的编写质量),像 Hotmail 这样的服务提供商也会将其视为垃圾邮件。我曾考虑将此作为答案,但它并没有确切回答你的问题...而且我也对能够正常工作的东西感兴趣。 - Tim Post
@Tim Post:感谢您的评论,这也是我目前实现的内容...我希望有人能提出解决方案或至少能解释为什么会发生这种情况。 - Alix Axel
1
请注意,这里的“成功”是指“在任何地方都能正常工作”,而不是“在Google上可以工作但在foomail上不太行”。有错误的远程MTA至少是它出现问题的部分原因(或者说,是它们使用的解析器)。 - Tim Post
1
+1 鼓励自己编写邮件发送器。 - Stephano
2个回答

47

在目标电子邮件服务器上,BCC地址不会被剥离。它不是这样工作的。

SMTP的实际工作原理

  • 发件人将向SMTP服务器发送一系列RCPT TO命令,每个接收者的电子邮件地址都有一个命令,并且此命令不区分接收者是普通的To、CC还是BCC类型的接收者。
  • 在告诉SMTP服务器谁是发件人,谁是服务器以及其他所有内容之后不久,发件人将调用DATA命令,其中包含电子邮件的内容-包括电子邮件头和正文-由电子邮件客户端接收。这些电子邮件头中包括常规的发件人地址、收件人地址、抄送地址。
  • BCC地址不会显示给接收者,只是因为它没有在DATA命令下打印出来,而不是因为目标SMTP服务器除去了它们。目标SMTP服务器只会参考RCPT TO中列出的应该接收电子邮件内容的电子邮件地址列表。它并不真正关心收件者是否在To、CC或BCC列表中。
    更新(以澄清):BCC电子邮件地址必须列在RCPT TO命令列表中,但BCC头不应在DATA命令下打印。

引用我认为与您的情况相关的RFC的一部分:

请注意,邮件数据包括备忘录标题项,例如日期、主题、收件人、抄送、发件人[2]。

推出自己的电子邮件发件人

几年前,诚实地说,我认为这是很久以前的事情,假设您仍然记忆犹新端到端的RFC 821。:)


@Alix:我明白了。你有检查过你发送的邮件和mail()发送的邮件之间原始内容(邮件头+正文)是否有任何差异,然后尝试使它们相同吗?或者使用一些免费的SMTP服务器应用程序安装在你的机器上,这将允许你检查发件人和SMTP服务器之间的整个“对话”(这是我能给出任何自己意见的范围,没有足够的知识来建议如何进一步调试SMTP问题)。 - Amry
1
@Alix:我相信我在第三点中已经说过,BCC不应该作为“DATA”命令的一部分打印,但它肯定应该出现在“RCPT TO”列表中。 - Amry
@Alix:如果我没记错的话,你只需要针对每个接收SMTP服务器打开新连接。如果地址包括例如people@yahoo.compeople@gmail.com,则肯定必须至少打开两个连接-每个接收服务器一个。 - Amry
1
@Alix:另外一件事,当您发送到两个(或更多)不同的服务器时,您还应相应地拆分“RCPT TO”命令,即当您连接到yahoo.com SMTP服务器时,您不会想要调用“RCPT TO:people@gmail.com”。 - Amry
@Alix:在编写代码之前测试 SMTP 的另一种方法是使用 Telnet 连接到 SMTP 端口上的服务器,您可以与服务器进行“SMTP 对话”,并在此过程中查看结果。 - Amry
显示剩余11条评论

21

虽然已经很晚了,但接受的答案基本上是错误的。

首先,SMTP与BCC没有任何关系。作为协议的SMTP只关心回退路径(MAIL请求)、收件人列表(RCPT请求)和要传输的数据(DATA请求)。如果您想通过SMTP向某人发送电子邮件,则必须在RCPT请求中提供其地址,就这么简单。

电子邮件的内容-即DATA - 是在RFC 2822中完全分别指定的。处理BCC有很大的灵活性。规范给出了处理BCC的3种方式,其中只有一种在准备电子邮件时剥离了BCC。例如,如果我使用电子邮件客户端Thunderbird,将其指向SMTP服务器,然后查看该行上的消息,那么我会发现Thunderbird的BCC已经消失了(从SMTPDATA中),SMTP连接代替它包含了一个标准的RCPT请求,用于的地址。因此,Thunderbird将BCC转换为RCPT,但这不是唯一的方法。

在处理BCC的另一个地方是在MTA(邮件传输代理) - 换句话说,无论您的邮件客户端指向哪个SMTP服务器。例如,Sendmail会搜索SMTP DATA中所有ToCcBcc行,然后从这些行构建地址列表,然后删除Bcc行。如果您想要保留Bcc,可以说服Sendmail保留它。如果sendmail不是目标MTA,则会通过SMTP连接到另一个MTA,并通过RCPT发送收件人地址。换句话说,如果sendmail是目标MTA,并且收到了Bcc,则将其删除,与Amry的声明相反。

评论中也存在一些混淆。您可以向任何域名指定RCPT地址,而不仅仅是同一域中地址的列表。 MTA必须查找目标域的MX记录,以确定将所有内容发送到哪里。 google.com和yahoo.com的说明是错误的。


1
我已经使用这个答案作为基础来修改Rebol SEND函数,以更好地处理CC和BCC字段。到目前为止,我的测试表明它按照描述的方式工作。 - rgchris
是否删除BCC取决于软件,而不是协议。依赖sendmail或任何其他MTA来删除它是不好的做法,只要您可以确保自己删除它。 - Michael Chourdakis
也许SMTP服务器没有删除Bcc头,因为它们不必要这样做。Amry提供的答案是完全正确的。 - rds
Amry的回答没有解决OP的问题,因此是错误的。它包含一些关于SMTP操作的细节,这些细节既不相关,也不正确,特别是在它声称“BCC地址不会显示给接收者,仅仅是因为它在DATA命令下没有被打印出来”的地方。它还未能指出相关的RFC是2822,与SMTP无关。 - EML

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接