You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel项目中如何在邮件中使用AWS S3非公开图片

问题描述

我有一个基于Laravel的项目,使用Illuminate\Support\Facades\Mail发送邮件,纯文本邮件发送正常。项目部署在AWS上,图片存储在非公开的AWS S3存储桶中,现在需要在邮件中嵌入这些S3里的图片。

当前邮件构建代码如下:

public function build()
{
    $this->subject('You have missed an interaction scheduled for ' . $this->schedule->clientname);
    return $this->view('emails.scheduleMissedCheckinToWorker')
        ->replyTo( $this->schedule->schedulerEmail,  $this->schedule->schedulername )
        ->with([
          'schedule' => $this->schedule,
         ]);
}

我已获取到图片在AWS的完整路径,但尝试了ChatGPT提供的方案后无效,该方案代码如下:

public function build()
{
    // Retrieve the image from S3
    $imageData = Storage::disk('s3')->get($this->missedSchedule->worker_image_path);

    return $this->view('emails.scheduleMissedCheckin')
        ->subject('An interaction you scheduled for ' . $this->missedSchedule->clientname . ' was not checked into by ' . $this->missedSchedule->workername)
        ->replyTo($this->missedSchedule->workerEmail, $this->missedSchedule->workername)
        ->with(['missedSchedule' => $this->missedSchedule])
        ->attachData($imageData, 'worker.jpg', [
            'mime' => 'image/jpeg',
            'as' => 'worker.jpg',
            'content_id' => 'workerImage'
        ])
        ->withSwiftMessage(function ($message) {
            $message->embedFromPath('worker.jpg', 'workerImage');
        });
}

Blade视图中使用:

<img src="cid:workerImage" alt="Worker Image" width="200" height="200">

需要有效的解决方法。

解决方案

方法一:使用Laravel邮件内置的embedData方法(推荐)

ChatGPT方案的核心问题是同时调用了attachData和embedFromPath,导致CID冲突。正确的做法是直接通过embedData生成嵌入图片的CID,再传递到视图:

public function build()
{
    // 从S3获取图片原始数据
    $imageData = Storage::disk('s3')->get($this->schedule->worker_image_path);
    // 动态获取图片MIME类型,避免硬编码错误
    $mimeType = Storage::disk('s3')->mimeType($this->schedule->worker_image_path);
    // 生成嵌入图片的CID
    $imageCid = $this->embedData($imageData, 'worker-image.jpg', [
        'mime' => $mimeType
    ]);

    $this->subject('You have missed an interaction scheduled for ' . $this->schedule->clientname);
    return $this->view('emails.scheduleMissedCheckinToWorker')
        ->replyTo($this->schedule->schedulerEmail, $this->schedule->schedulername)
        ->with([
            'schedule' => $this->schedule,
            'workerImageCid' => $imageCid // 将CID传递到视图
        ]);
}

在Blade视图中引用:

<img src="{{ $workerImageCid }}" alt="Worker Image" width="200" height="200">

方法二:生成S3临时公开URL

如果不想将图片作为邮件附件发送(可减少邮件体积),可以生成S3的预签名临时URL,有效期可自定义:

public function build()
{
    // 生成有效期1小时的S3临时URL
    $imageUrl = Storage::disk('s3')->temporaryUrl(
        $this->schedule->worker_image_path,
        now()->addHour()
    );

    $this->subject('You have missed an interaction scheduled for ' . $this->schedule->clientname);
    return $this->view('emails.scheduleMissedCheckinToWorker')
        ->replyTo($this->schedule->schedulerEmail, $this->schedule->schedulername)
        ->with([
            'schedule' => $this->schedule,
            'workerImageUrl' => $imageUrl
        ]);
}

Blade视图中引用:

<img src="{{ $workerImageUrl }}" alt="Worker Image" width="200" height="200">

方法三:修复ChatGPT的方案(不推荐)

如果要保留类似ChatGPT的写法,只需去掉重复的embedFromPath调用,attachData已经通过content_id设置了CID:

public function build()
{
    $imageData = Storage::disk('s3')->get($this->missedSchedule->worker_image_path);
    $mimeType = Storage::disk('s3')->mimeType($this->missedSchedule->worker_image_path);

    return $this->view('emails.scheduleMissedCheckin')
        ->subject('An interaction you scheduled for ' . $this->missedSchedule->clientname . ' was not checked into by ' . $this->missedSchedule->workername)
        ->replyTo($this->missedSchedule->workerEmail, $this->missedSchedule->workername)
        ->with(['missedSchedule' => $this->missedSchedule])
        ->attachData($imageData, 'worker.jpg', [
            'mime' => $mimeType,
            'content_id' => 'workerImage' // 仅保留此处设置CID
        ]);
}

视图保持不变:

<img src="cid:workerImage" alt="Worker Image" width="200" height="200">

注意事项

  • 确保Laravel的S3磁盘配置正确,拥有目标图片的读取权限;
  • 方法一中的embedData会将图片作为邮件内嵌附件发送,适合小尺寸图片;
  • 方法二中的临时URL需要确保邮件接收方能访问AWS S3公网地址,适合大尺寸图片;
  • 避免硬编码MIME类型,建议使用Storage::disk('s3')->mimeType()动态获取。

内容的提问来源于stack exchange,提问作者user761100

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:03:16