Laravel中如何保存PHP-MIME-MAIL-PARSE捕获、fopen读取的邮件文件?
问题原因
你现有代码保存失败有两个核心问题:
- 调用
$parser->setStream()后返回的是邮件解析器实例对象,不是原始邮件内容,无法直接传入存储方法 putFileAs方法要求第二个参数为文件路径/UploadedFile实例,保存字符串内容需要用put方法
另外要注意php://stdin是只读单次流,被解析器消费后指针会走到末尾,后续再读取会拿到空内容,所以要先读取完整原始内容再交给解析器处理。
方案1:直接存储原始邮件副本
适合需要单独存储每封邮件为独立文件的场景:
// 先读取完整原始邮件内容 $rawMail = file_get_contents('php://stdin'); // 再初始化解析器处理内容 $parser = new Parser(); $doc = $parser->setText($rawMail); // 生成带后缀的文件名,方便后续识别 $nameFile = $website->hostnames->implode('fqdn') . '_' . time() . '.eml'; // 存储原始内容到指定磁盘 Storage::disk('tenancy')->put($website->id . '/' . $nameFile, $rawMail);
方案2:通过日志轮转实现备份
符合你提到的后续用日志轮转工具维护的需求,Laravel自带的日志通道就支持自动按周期轮转、清理旧日志,无需自己实现文件管理逻辑:
- 先在
config/logging.php中新增专属日志通道
'channels' => [ // 原有其他通道保持不变 'raw_mail' => [ 'driver' => 'daily', 'path' => storage_path('logs/raw_mails.log'), 'level' => 'debug', 'days' => 30, // 自定义保留多少天的邮件备份 'permission' => 0644, ], ]
- 接收邮件时直接写入日志即可,可附加业务信息方便后续排查
// 读取原始邮件内容 $rawMail = file_get_contents('php://stdin'); $hostname = $website->hostnames->implode('fqdn'); // 写入日志,增加分隔符方便后续拆分单封邮件 Log::channel('raw_mail')->info("=== 接收邮件开始 | 主机名:{$hostname} | 时间:".date('Y-m-d H:i:s')." ==="); Log::channel('raw_mail')->info($rawMail); Log::channel('raw_mail')->info("=== 接收邮件结束 ==="); // 后续正常走解析逻辑 $parser = new Parser(); $doc = $parser->setText($rawMail);
两种方案都兼容你纯文本无附件的邮件场景,方案2的运维成本更低,不需要额外处理文件清理、磁盘占用统计等问题。
内容的提问来源于stack exchange,提问作者alex spencer
相关产品推荐
相关产品推荐

