使用PHP 7.1通过cURL发送邮件时主题、正文为空且收件人显示“undisclosed recipients”的问题排查
问题分析与修复方案
你遇到的问题核心是混淆了SMTP协议和HTTP协议的用法,同时代码里还有几处语法和参数配置错误,导致邮件内容无法被正确解析。咱们一步步拆解问题:
关键错误点
- 错误用HTTP方式处理SMTP请求:SMTP是独立的邮件传输协议,根本不需要
CURLOPT_POST、CURLOPT_POSTFIELDS、CURLOPT_HTTPHEADER这些HTTP请求参数,你加的这些配置对SMTP发送完全无效。 - 字符串语法错误:
$postData里的John Doe、A simple test没有用引号包裹,这会直接触发PHP语法错误,后续数据处理自然出问题。 - curl_setopt_array配置格式错误:数组里嵌套了
curl_setopt($ch, CURLOPT_POST, true),这是非法写法,数组元素必须是[选项常量 => 值]的格式。 - 缺少SMTP邮件内容的正确传递逻辑:SMTP发送需要传递符合RFC 2822规范的完整邮件内容,而不是用POST字段传递零散参数。
修正后的代码示例
下面是符合SMTP规范的正确写法,我们会构造完整的邮件内容,用cURL的SMTP模式发送:
<?php // 修复字符串引号问题,整理邮件基础信息 $fromName = "John Doe"; $fromEmail = "no-reply@mydomain.com"; $toEmail = "xxxxxxxx@yyyyy.zzz"; $subject = "A simple test"; $body = "this is a test"; // 构造符合RFC 2822标准的邮件内容 $mimeBoundary = md5(time()); $emailContent = <<<EMAIL From: "$fromName" <$fromEmail> To: <$toEmail> Subject: $subject MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="$mimeBoundary" --$mimeBoundary Content-Type: text/plain; charset=utf-8 $body --$mimeBoundary-- EMAIL; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'smtp://smtp.mydomain.com:25', // 注意SMTP的URL格式是smtp://开头 CURLOPT_MAIL_FROM => "<$fromEmail>", CURLOPT_MAIL_RCPT => ["<$toEmail>"], // 收件人需要用<>包裹格式 CURLOPT_UPLOAD => true, // 传递构造好的邮件内容 CURLOPT_INFILE => fopen('php://temp', 'r+'), CURLOPT_INFILESIZE => strlen($emailContent), CURLOPT_READFUNCTION => function($ch, $fd, $length) use ($emailContent) { static $offset = 0; $data = substr($emailContent, $offset, $length); $offset += strlen($data); return $data; }, // 可选:开启调试模式查看SMTP交互过程(排查问题用) // CURLOPT_VERBOSE => true, // CURLOPT_STDERR => fopen('smtp_debug.log', 'w'), ]); $result = curl_exec($ch); if (!$result) { echo "发送失败: " . curl_error($ch); } else { echo "邮件发送成功"; } curl_close($ch); ?>
额外说明
- SMTP URL格式:正确的SMTP地址应该是
smtp://smtp.mydomain.com:25,你之前写的smtp.mydomain.com:25/mydomain.com是HTTP路径的写法,SMTP不需要路径。 - 邮件格式规范:必须包含
From、To、Subject等头信息,内容要符合MIME规范,这样邮件客户端才能正确解析主题、正文和收件人信息。 - SMTP认证:如果你的服务器需要用户名密码验证,还要添加
CURLOPT_USERPWD => "你的用户名:你的密码"参数。 - 端口选择:25是默认SMTP端口,但很多服务器要求用465(SSL)或587(TLS),如果25端口无法连接,可以切换端口并根据情况添加
CURLOPT_SSL_VERIFYPEER => false(测试环境临时用,生产环境建议配置正确的SSL证书)。
内容的提问来源于stack exchange,提问作者splunk
相关产品推荐
相关产品推荐

