
php 手动实现 smtp 邮件发送时,仅在邮件头中添加 `cc:` 字段不足以让抄送人收到邮件;必须在 smtp 协议层显式调用 `rcpt to:` 命令为每个 cc 地址注册收件人,否则邮件服务器会忽略该地址。
在您提供的自定义 smtp_mail() 函数中,当前逻辑仅对 $To 地址执行了 RCPT TO: 命令(即 SMTP 会话中声明合法收件人),但完全跳过了 $Cc 地址的 RCPT 注册步骤。SMTP 协议规定:所有实际接收邮件的地址(无论 To、Cc 还是 Bcc)都必须在 DATA 命令之前,通过独立的 RCPT TO: 指令明确告知服务器;而 To: 和 Cc: 等头部字段仅用于客户端显示和邮件内容组织,不参与投递路由。
因此,修复的关键是在 MAIL FROM: 之后、DATA 之前,为 CC 收件人补全 RCPT 流程:
// ✅ 正确:为 To 地址注册收件人
foreach ($recipients as $email) {
fwrite($socket, 'RCPT TO: <' . trim($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: 是强制性协议步骤:缺少任一收件人的 RCPT 命令,SMTP 服务器将拒绝向其投递,即使邮件头中已声明 Cc:。
- BCC 同理:若需密送,也需在 RCPT 阶段添加(但不在邮件头中体现)。
- 邮箱格式校验:建议对 $email 调用 trim() 和空值检查,避免因多余空格或空字符串导致 RCPT TO: 错误。
- 安全性提醒:示例代码中硬编码了 SMTP 账户凭证($user/$pass)且未启用认证(注释掉了 AUTH LOGIN)。生产环境务必启用 TLS/SSL 加密(如端口 587 + STARTTLS)并使用应用专用密码或 OAuth2,切勿明文暴露凭据。
- 现代替代方案:强烈建议迁移到成熟库(如 PHPMailer 或 Symfony Mailer),它们自动处理 RCPT、MIME 编码、错误重试及安全连接,大幅降低协议误用风险。
完成上述修改后,CC 收件人即可正常接收邮件——因为 SMTP 层已正式接纳他们为合法收件人,邮件头中的 Cc: 字段则确保他们在邮件客户端中正确显示为“抄送”。
立即学习“PHP免费学习笔记(深入)”;











