📧 在 Laravel 中使用 CID 图像发送电子邮件的教程

在本教程中,我们将学习如何在 Laravel 中使用**CID(内容ID)**发送带有静态图像的电子邮件。通过这种方法,即使收件人处于离线状态,图像也可以正常显示。

Tags:
  • #Laravel
  • #电子邮件
  • #CID 图像
  • #PHP
  • #邮件
Learning Path: | Category: Laravel 技巧

📌 目录

  1. 简介
  2. 准备工作
  3. 创建邮件助手
  4. 使用 CID 图像创建邮件视图
  5. 使用助手发送邮件
  6. 结论

🔧 准备工作

  1. 确保已安装 Laravel。
  2. .env 中配置 SMTP:
    MAIL_MAILER=smtp
    MAIL_HOST=smtp.example.com
    MAIL_PORT=587
    MAIL_USERNAME=your_email@example.com
    MAIL_PASSWORD=your_password
    MAIL_ENCRYPTION=tls
    MAIL_FROM_ADDRESS=your_email@example.com
    MAIL_FROM_NAME="你的名字"
  3. 运行 php artisan storage:link 以访问存储中的图像。

📌 创建邮件助手

创建 app/Helpers/EmailHelper.php

<?php

namespace App\Helpers;

use Illuminate\Support\Facades\Mail;
use Exception;

class EmailHelper
{
    public static function sendEmail($to, $subject, $message, $attachments = [], $cc = [], $bcc = [])
    {
        try {
            Mail::send([], [], function ($messageObj) use ($to, $subject, $message, $attachments, $cc, $bcc) {
                $messageWithInlineImages = self::processInlineImages($message, $messageObj);
                
                $messageObj->to($to)
                           ->subject($subject)
                           ->html($messageWithInlineImages);
                
                if (!empty($cc)) $messageObj->cc($cc);
                if (!empty($bcc)) $messageObj->bcc($bcc);
                if (!empty($attachments)) {
                    foreach ($attachments as $attachment) {
                        $messageObj->attach($attachment);
                    }
                }
            });

            return true;
        } catch (Exception $e) {
            logger("EmailHelper: " . $e->getMessage());
            throw new Exception("发送邮件失败:" . $e->getMessage());
        }
    }

    private static function processInlineImages($body, $messageObj)
    {
        return preg_replace_callback('/<img[^>]+src=["\'](.*?)["\']/i', function ($matches) use ($messageObj) {
            $imagePath = $matches[1];
            
            if (strpos($imagePath, '/storage') === 0) {
                $filePath = storage_path('app/public' . parse_url($imagePath, PHP_URL_PATH));
                
                if (file_exists($filePath)) {
                    $cid = 'cid_' . uniqid();
                    $messageObj->embed($filePath, ['content-id' => $cid]);
                    return 'src="cid:' . $cid . '"';
                }
            }
            
            return $matches[0];
        }, $body);
    }
}

🖼 使用 CID 图像创建邮件视图

创建 resources/views/emails/sample.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>带有 CID 图像的电子邮件</title>
</head>
<body>
    <h2>你好,这是一封带有 CID 图像的电子邮件</h2>
    <p>以下是内嵌图像:</p>
    <img src="/storage/email/logo.png" alt="标志">
</body>
</html>

确保图像存储在 storage/app/public/email/logo.png


🔍 理解 processInlineImages

processInlineImages 函数负责将本地路径的图像(/storage/...)转换为内容 ID(CID),以便在电子邮件中作为内嵌附件包含。

工作原理:

  1. 使用 preg_replace_callback 检测电子邮件中的 <img> 标签
  2. 提取 <img> 标签的 src 以检查图像是否来自 Laravel 存储(/storage/...)。
  3. 使用 storage_path() 将图像路径转换为服务器上的绝对路径
  4. 使用 $messageObj->embed() 将图像嵌入电子邮件,进行 CID 图像编码
  5. 将 HTML 中的图像 src 替换为 cid:unique_id,使图像从电子邮件而非外部 URL 显示。

HTML 电子邮件转换示例:

转换前:

<img src="/storage/email/logo.png" alt="标志">

转换后:

<img src="cid:cid_123456789" alt="标志">

通过这种方法,即使收件人离线,图像也能正常显示。


📤 使用助手发送邮件

在控制器或服务中,使用以下代码发送电子邮件:

use App\Helpers\EmailHelper;

EmailHelper::sendEmail(
    'recipient@example.com',
    '电子邮件主题',
    view('emails.sample')->render()
);

✅ 结论

通过这种方法,即使收件人离线,电子邮件中的图像也能正常显示。这对于发送包含品牌或重要图像的电子邮件非常有用,无需依赖外部源。

祝编程愉快! 🎉

Logo Adib

© 2025 Adib

GitHub