Laravel 9邮件日志与数据库存储字符畸形问题求助
解决Laravel 9中邮件日志/数据库存储的字符畸形问题
你遇到的=3D、=C3=A4这类字符是Quoted-Printable编码——这是邮件传输协议中用于处理非ASCII字符和特殊符号的标准编码方式。SMTP驱动会自动解码显示正常内容,但log驱动和部分第三方日志包直接存储了编码后的原始内容,导致显示畸形。以下是针对本地和生产环境的解决方案:
一、本地Log驱动的字符修复
自定义Log邮件驱动(优雅方案)
通过重写Laravel的Log邮件驱动,在日志输出前自动解码内容:
- 创建自定义Mailer类:
// app/Mail/CustomLogMailer.php namespace App\Mail; use Illuminate\Mail\Mailers\LogMailer; use Illuminate\Mail\Message; use Symfony\Component\Mime\MessageConverter; use Symfony\Component\Mime\Decoder\QuotedPrintableDecoder; class CustomLogMailer extends LogMailer { protected function sendMessage(Message $message): void { $symfonyMessage = MessageConverter::toSymfony($message); $decoder = new QuotedPrintableDecoder(); // 解码HTML内容 if ($symfonyMessage->getHtmlBody()) { $decodedHtml = $decoder->decode($symfonyMessage->getHtmlBody()); $symfonyMessage->html($decodedHtml); } // 解码纯文本内容(如果存在) if ($symfonyMessage->getTextBody()) { $decodedText = $decoder->decode($symfonyMessage->getTextBody()); $symfonyMessage->text($decodedText); } $this->logger->info($symfonyMessage->toString()); } }
- 在
AppServiceProvider中注册自定义驱动:
// app/Providers/AppServiceProvider.php use App\Mail\CustomLogMailer; use Illuminate\Mail\MailManager; public function boot() { $this->app->extend(MailManager::class, function ($manager, $app) { $manager->extend('custom-log', function ($app) { return new CustomLogMailer($app['log']); }); return $manager; }); }
- 修改.env配置:
MAIL_MAILER=custom-log
之后日志文件中就会显示解码后的正常字符。
二、生产环境数据库存储的解决方案
方案1:修复第三方包的编码问题
针对shvetsgroup/laravel-email-database-log包,我们可以绕过其默认存储逻辑,自己监听邮件发送事件并解码存储:
- 禁用原包自动存储:在
config/email-log.php中设置enabled=false - 创建事件监听器:
// app/Listeners/LogEmailToDatabase.php namespace App\Listeners; use Illuminate\Mail\Events\MessageSent; use Illuminate\Support\Facades\DB; use Symfony\Component\Mime\MessageConverter; use Symfony\Component\Mime\Decoder\QuotedPrintableDecoder; class LogEmailToDatabase { public function handle(MessageSent $event) { $symfonyMessage = MessageConverter::toSymfony($event->message); $decoder = new QuotedPrintableDecoder(); $htmlBody = $symfonyMessage->getHtmlBody() ? $decoder->decode($symfonyMessage->getHtmlBody()) : null; $textBody = $symfonyMessage->getTextBody() ? $decoder->decode($symfonyMessage->getTextBody()) : null; DB::table('email_log')->insert([ 'from' => implode(', ', array_map(fn($addr) => $addr->getAddress(), $symfonyMessage->getFrom())), 'to' => implode(', ', array_map(fn($addr) => $addr->getAddress(), $symfonyMessage->getTo())), 'cc' => implode(', ', array_map(fn($addr) => $addr->getAddress(), $symfonyMessage->getCc() ?? [])), 'bcc' => implode(', ', array_map(fn($addr) => $addr->getAddress(), $symfonyMessage->getBcc() ?? [])), 'subject' => $symfonyMessage->getSubject(), 'body' => $htmlBody ?? $textBody, 'headers' => json_encode($symfonyMessage->getHeaders()->all()), 'created_at' => now(), 'updated_at' => now(), ]); } }
- 在
EventServiceProvider中注册监听器:
// app/Providers/EventServiceProvider.php protected $listen = [ \Illuminate\Mail\Events\MessageSent::class => [ \App\Listeners\LogEmailToDatabase::class, ], ];
方案2:完全自定义邮件数据库日志(无第三方依赖)
如果不想使用第三方包,直接用上述监听器方案即可,只需要提前创建存储表:
CREATE TABLE email_log ( id INT AUTO_INCREMENT PRIMARY KEY, `from` VARCHAR(255) NOT NULL, `to` TEXT NOT NULL, cc TEXT NULL, bcc TEXT NULL, subject VARCHAR(255) NOT NULL, body TEXT NOT NULL, headers TEXT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
配合监听器就能实现无编码问题的邮件存储。
内容的提问来源于stack exchange,提问作者klediooo
相关产品推荐
相关产品推荐

