
使用 php 手动实现 smtp 邮件发送时,仅在邮件头中添加 `cc` 字段无法使抄送人收到邮件;必须在 smtp 协议层显式声明每个 cc 收件人为 rcpt to 目标。
在您提供的代码中,问题根源非常明确:SMTP 协议本身不识别邮件头中的 CC 字段。To、Cc 和 Bcc 语义完全由邮件客户端(如 Outlook、Gmail)在解析 RFC 5322 格式邮件体时解释,而 SMTP 传输阶段只关心“谁是实际收件人”——即所有需接收该邮件的地址,都必须通过 RCPT TO: 命令逐个注册到 SMTP 会话中。
当前代码仅对 $To 地址执行了 RCPT TO: 注册:
foreach ($recipients as $email) {
fwrite($socket, 'RCPT TO: <'.$email.'>'."\r\n");
server_parse($socket, '250');
}但完全忽略了 $Cc 地址,导致 SMTP 服务器根本不会向这些邮箱投递邮件,即使你在 DATA 阶段的邮件头里写了 Cc: xxx@example.com。
✅ 正确做法是:为每一个 CC 收件人也调用一次 RCPT TO:,就像处理主收件人一样:
立即学习“PHP免费学习笔记(深入)”;
// 注册 To 收件人
foreach ($recipients as $email) {
$email = trim($email);
if (!empty($email)) {
fwrite($socket, 'RCPT TO: <' . $email . '>' . "\r\n");
server_parse($socket, '250');
}
}
// ✅ 关键修复:注册 CC 收件人(注意去空格和空值校验)
foreach ($recipientscc as $email) {
$email = trim($email);
if (!empty($email)) {
fwrite($socket, 'RCPT TO: <' . $email . '>' . "\r\n");
server_parse($socket, '250');
}
}⚠️ 注意事项:
- RCPT TO: 必须在 DATA 命令之前完成,且每个地址需独立发送并等待 250 OK 响应;
- 邮件头中的 Cc: 字段仍需保留(用于客户端显示),但它纯属元信息,不影响投递逻辑;
- 若 Cc 字符串含空格或换行(如 "a@b.com, c@d.com"),explode(',', $cc) 可能产生带前导空格的邮箱,务必 trim();
- BCC 同理:需 RCPT TO: 注册,但不能出现在邮件头中(否则就不是“密送”了);
- 当前代码未启用认证(注释掉的 AUTH LOGIN),若 SMTP 服务器要求登录(如 Gmail、Outlook 或企业邮件网关),将连接失败或被拒收——生产环境务必启用 SASL 认证并使用 TLS/SSL(端口 465 或 587)。
? 总结:SMTP 是“投递协议”,不是“展示协议”。To/Cc/Bcc 的业务含义由 MUA(邮件用户代理)渲染决定,而 RCPT TO: 列表才是 MTA(邮件传输代理)真正执行投递的唯一依据。修复后,您的自动化脚本即可正确送达所有收件人。











