💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# Mail - [简介](#introduction) - [邮件驱动预备知识](#driver-prerequisites) - [生成可邮寄类](#generating-mailables) - [编写可邮寄类](#writing-mailables) - [配置发件人](#configuring-the-sender) - [配置视图](#configuring-the-view) - [视图数据](#view-data) - [附件](#attachments) - [内联附件](#inline-attachments) - [自定义 SwiftMailer 消息](#customizing-the-swiftmailer-message) - [Markdown 邮件类](#markdown-mailables) - [生成 Markdown 邮件类](#generating-markdown-mailables) - [编写 Markdown 消息](#writing-markdown-messages) - [自定义组件](#customizing-the-components) - [发送邮件](#sending-mail) - [邮件队列](#queueing-mail) - [渲染可邮寄类](#rendering-mailables) - [在浏览器中预览邮件](#previewing-mailables-in-the-browser) - [本地化可邮寄类](#localizing-mailables) - [邮件 & 本地开发](#mail-and-local-development) - [事件](#events) <a name="introduction"></a> ## 简介 Laravel 基于 [SwiftMailer](https://swiftmailer.symfony.com/) 库提供了一套干净、清爽的邮件 API。Laravel 为 SMTP、Mailgun、SparkPost、Amazon SES、PHP 的 `mail` 函数,以及 `sendmail` 提供了驱动,从而允许你快速通过本地或云服务发送邮件。 <a name="driver-prerequisites"></a> ### 邮件驱动预备知识 基于 API 的驱动如 Mailgun 和 SparkPost 通常比 SMTP 服务器更简单、更快,所以如果可以的话,尽可能使用这些服务。所有的 API 驱动要求应用已经安装 Guzzle HTTP 库,你可以通过 Composer 包管理器来安装它: composer require guzzlehttp/guzzle #### Mailgun 驱动 要使用 Mailgun 驱动(Mailgun 前10000封邮件免费,后续收费),首先安装 Guzzle,然后在配置文件 `config/mail.php` 中设置 `driver` 选项为 `mailgun` 。接下来,验证配置文件 `config/services.php` 包含如下选项: 'mailgun' => [ 'domain' => 'your-mailgun-domain', 'secret' => 'your-mailgun-key', ], 如果您没有使用 “US” [Mailgun地区](https://documentation.mailgun.com/en/latest/api-intro.html#mailgun-regions) ,您可以在 `services` 中定义您所在地区的终端 配置文件: 'mailgun' => [ 'domain' => 'your-mailgun-domain', 'secret' => 'your-mailgun-key', 'endpoint' => 'api.eu.mailgun.net', ], #### Postmark 驱动程序 要使用Postmark驱动程序,请通过 Composer 安装 Postmark 的 SwiftMailer: composer require wildbit/swiftmailer-postmark 接下来,安装 Guzzle 并将 `config / mail.php` 配置文件中的 `driver` 选项设置为 `postmark`。 最后,验证您的 `config / services.php` 配置文件包含以下选项: 'postmark' => [ 'token' => 'your-postmark-token', ], #### SparkPost 驱动 要使用 SparkPost 驱动,首先安装 Guzzle,然后再配置文件 `config/mail.php` 中设置 `driver` 选项值为 `sparkpost` 。接下来,验证配置文件 `config/services.php` 包含如下选项: 'sparkpost' => [ 'secret' => 'your-sparkpost-key', ], 如果有必要的话,你还可以设置 [API 端点](https://developers.sparkpost.com/api/#header-endpoints)使用: 'sparkpost' => [ 'secret' => 'your-sparkpost-key', 'options' => [ 'endpoint' => 'https://api.eu.sparkpost.com/api/v1/transmissions', ], ], #### SES 驱动 要使用 Amazon SES 驱动(收费),先安装 Amazon AWS 的 PHP SDK,你可以通过添加如下行到 `composer.json` 文件的 `require` 部分然后运行 `composer update` 命令来安装该库: "aws/aws-sdk-php": "~3.0" 接下来,设置配置文件 `config/mail.php` 中的 `driver` 选项为 `ses` 。然后,验证配置文件 `config/services.php` 包含如下选项: 'ses' => [ 'key' => 'your-ses-key', 'secret' => 'your-ses-secret', 'region' => 'ses-region', // e.g. us-east-1 ], 如果您在执行SES时需要包含 [附加选项](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-email-2010-12-01.html#sendrawemail) `SendRawEmail`请求,您可以在 `ses` 配置中定义 `options` 数组: 'ses' => [ 'key' => 'your-ses-key', 'secret' => 'your-ses-secret', 'region' => 'ses-region', // e.g. us-east-1 'options' => [ 'ConfigurationSetName' => 'MyConfigurationSet', 'Tags' => [ [ 'Name' => 'foo', 'Value' => 'bar', ], ], ], ], <a name="generating-mailables"></a> ## 生成可邮寄类 在 Laravel 中,应用发送的每一封邮件都可以表示为“可邮寄”类,这些类都存放在 `app/Mail` 目录。如果没看到这个目录,别担心,它将会在你使用 `make:mail` 命令创建第一个可邮寄类时生成: php artisan make:mail OrderShipped <a name="writing-mailables"></a> ## 编写可邮寄类 所有的可邮寄类配置都在 `build` 方法中完成,在这个方法中,你可以调用多个方法,例如 `from`,`subject`, `view`, 和 `attach` 来配置邮件的内容和发送。 <a name="configuring-the-sender"></a> ### 配置发件人 #### 使用 `from` 方法 我们来看一下邮件发件人的配置,或者,换句话说,邮件来自于谁。有两种方式来配置发送者,第一种方式是在可邮寄类的 `build` 方法方法中调用 `from` 方法: /** * 构建消息. * * @return $this */ public function build() { return $this->from('example@example.com') ->view('emails.orders.shipped'); } #### 使用全局的 `from` 地址 不过,如果你的应用在所有邮件中都使用相同的发送地址,在每个生成的可邮寄类中都调用 `from` 方法就显得很累赘。取而代之地,你可以在配置文件 `config/mail.php` 中指定一个全局的发送地址, 如果在 mailable 类中未指定其他 `from` 地址,则将使用此地址: 'from' => ['address' => 'example@example.com', 'name' => 'App Name'], 此外,您可以在 `config / mail.php` 配置文件中定义全局 `reply_to` 地址: 'reply_to' => ['address' => 'example@example.com', 'name' => 'App Name'], <a name="configuring-the-view"></a> ### 配置视图 你可以在可邮寄类的 `build` 方法中使用 `view` 方法来指定渲染邮件内容时使用哪个视图模板,由于每封邮件通常使用 [Blade 模板](/docs/{{version}}/blade)来渲染内容,所以你可以在构建邮件 HTML 时使用 Blade 模板引擎提供的所有功能: /** * 构建消息. * * @return $this */ public function build() { return $this->view('emails.orders.shipped'); } > {注:} 你可以创建一个 `resources/views/emails` 目录来存放所有邮件模板,当然,你也可以将邮件模板放到 `resources/views` 目录下任意其它位置。 #### 纯文本邮件 如果你想要定义一个纯文本格式的邮件,可以使用 `text` 方法。和 `view` 方法一样, `text` 方法接收一个用于渲染邮件内容的模板名,你既可以定义纯文本消息也可以定义 HTML 消息: /** * 构建消息. * * @return $this */ public function build() { return $this->view('emails.orders.shipped') ->text('emails.orders.shipped_plain'); } <a name="view-data"></a> ### 视图数据 #### 通过公共属性 通常,我们需要传递一些数据到渲染邮件的 HTML 视图以供使用。有两种方式将数据传递到视图,首先,您的 mailable 类中定义的任何公共属性将自动传递给视图。 因此,您可以将数据传递到 mailable 类的构造函数,并将该数据设置为类的公共属性: <?php namespace App\Mail; use App\Order; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class OrderShipped extends Mailable { use Queueable, SerializesModels; /** * 订单实例. * * @var Order */ public $order; /** * 创建一个新的消息实例. * * @return void */ public function __construct(Order $order) { $this->order = $order; } /** * 构建消息. * * @return $this */ public function build() { return $this->view('emails.orders.shipped'); } } 数据被设置给公共属性后,将会在视图中自动生效,所以你可以像在 Blade 模板中访问其它数据一样访问它们: <div> Price: {{ $order->price }} </div> #### 通过 `with` 方法 如果你想要在数据发送到模板之前自定义邮件数据的格式,可以通过 `with` 方法手动传递数据到视图。一般情况下,你还是需要通过可邮寄类的构造器传递数据,不过,这次你需要设置数据为 `protected` 或 `private` 属性,这样,这些数据就不会在视图中自动生效。然后,当调用 `with` 方法时,传递数组数据到该方法以便数据在视图模板中生效: <?php namespace App\Mail; use App\Order; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class OrderShipped extends Mailable { use Queueable, SerializesModels; /** * 订单实例. * * @var Order */ protected $order; /** * 创建一个新的实例. * * @return void */ public function __construct(Order $order) { $this->order = $order; } /** * 构建消息. * * @return $this */ public function build() { return $this->view('emails.orders.shipped') ->with([ 'orderName' => $this->order->name, 'orderPrice' => $this->order->price, ]); } } 数据通过 `with` 方法传递到视图后,将会在视图中自动生效,因此你也可以像在 Blade 模板访问其它数据一样访问传递过来的数据: <div> Price: {{ $orderPrice }} </div> <a name="attachments"></a> ### 附件 要在邮件中加入附件,在 `build` 方法中使用 `attach` 方法。`attach` 方法接受文件的绝对路径作为它的第一个参数: /** * Build the message. * * @return $this */ public function build() { return $this->view('emails.orders.shipped') ->attach('/path/to/file'); } 附加文件到消息时,你也可以传递 `数组` 给 `attach` 方法作为第二个参数,以指定显示名称和 / 或是 MIME 类型: /** * Build the message. * * @return $this */ public function build() { return $this->view('emails.orders.shipped') ->attach('/path/to/file', [ 'as' => 'name.pdf', 'mime' => 'application/pdf', ]); } #### 从磁盘中添加附件 如果您已在[文件存储](/docs/{{version}}/filesystem)上存储了一个文件,则可以使用 `attachFromStorage` 方法将其附加到电子邮件中: /** * 构建消息。 * * @return $this */ public function build() { return $this->view('email.orders.shipped') ->attachFromStorage('/path/to/file'); } 如有必要,您可以使用 `attachFromStorage` 方法的第二个和第三个参数指定文件的附件名称和其他选项: /** * 构建消息。 * * @return $this */ public function build() { return $this->view('email.orders.shipped') ->attachFromStorage('/path/to/file', 'name.pdf', [ 'mime' => 'application/pdf' ]); } 如果需要指定默认磁盘以外的存储磁盘,可以使用 `attachFromStorageDisk` 方法: /** * 构建消息。 * * @return $this */ public function build() { return $this->view('email.orders.shipped') ->attachFromStorageDisk('s3', '/path/to/file'); } #### 原始数据附件 `attachData` 可以使用字节数据作为附件。例如,你可以使用这个方法将内存中生成而没有保存到磁盘中的 PDF 附加到邮件中。`attachData` 方法第一个参数接收原始字节数据,第二个参数为文件名,第三个参数接受一个数组以指定其他参数: /** * Build the message. * * @return $this */ public function build() { return $this->view('emails.orders.shipped') ->attachData($this->pdf, 'name.pdf', [ 'mime' => 'application/pdf', ]); } <a name="inline-attachments"></a> ### 内联附件 在邮件中嵌入内联图片通常都很麻烦;不过,Laravel 提供了向邮件中附加图片并获取适当的 CID 的简便方法。可以使用邮件模板中 `$message` 变量的 `embed` 方法来嵌入内联图片。Laravel 自动使 `$message` 变量在全部邮件模板中可用,不需要担心如何手动传递它: <body> Here is an image: <img src="{{ $message->embed($pathToImage) }}"> </body> > {note} `$message` 在文本消息中不可用,因为文本消息不能使用内联附件。 #### 嵌入原始数据附件 如果已经有了希望嵌入邮件模板的原始数据串,可以使用 `$message` 变量的 `embedData` 方法: <body> Here is an image from raw data: <img src="{{ $message->embedData($data, $name) }}"> </body> <a name="customizing-the-swiftmailer-message"></a> ### 自定义 SwiftMailer 消息 `Mailable` 基类的 `withSwiftMessage` 方法允许你注册一个回调,它将在发送消息之前被调用,原始的 SwiftMailer 消息将作为该回调的参数: /** * 构建消息。 * * @return $this */ public function build() { $this->view('emails.orders.shipped'); $this->withSwiftMessage(function ($message) { $message->getHeaders() ->addTextHeader('Custom-Header', 'HeaderValue'); }); } <a name="markdown-mailables"></a> ## Markdown 格式的 Mailables 类 Markdown 格式 mailable 消息允许你从预构建模板和 mailable 类中的邮件通知组件获益。由于消息使用 Markdown 书写,Laravel 能够渲染出美观的、响应式的 HTML 模板消息,还能自动生成文本副本。 <a name="generating-markdown-mailables"></a> ### 生成 Markdown 格式的 Mailables 类 要生成一个适用 Markdown 模板的 mailable,可以使用带有 `--markdown` 选项的 `make:mail` Artisan 命令: php artisan make:mail OrderShipped --markdown=emails.orders.shipped 然后,在它的 `build` 方法中配置 mailable,调用 `markdown` 方法代替 `view` 方法。 `markdown` 方法接受 Markdown 模板名和一个可选的在模板中可用的数组: /** * Build the message. * * @return $this */ public function build() { return $this->from('example@example.com') ->markdown('emails.orders.shipped'); } <a name="writing-markdown-messages"></a> ### 编写 Markdown 消息 Markdown mailable 使用 Blade 组件和 Markdown 语法组合,让你可以更方便地利用 Laravel 预制组件构建邮件消息: @component('mail::message') # 订单已发货 Your order has been shipped! @component('mail::button', ['url' => $url]) View Order @endcomponent Thanks,<br> {{ config('app.name') }} @endcomponent > {tip} 编写 Markdown 邮件时不要使用额外的缩进。Markdown 解析器将把缩进内容渲染成代码块。 #### 按钮组件 按钮组件渲染一个居中按钮链接。此组建接受两个参数, `url` 和可选的 `color`。颜色选项支持 `primary`、 `success` 和 `error`。你可以随心所欲地向消息添加任意数量的按钮组件: @component('mail::button', ['url' => $url, 'color' => 'success']) View Order @endcomponent #### 面板组件 面板组件在面板内渲染给定的文字块,面板与其他消息的背景色略有不同。能让你绘制一个警示文字块: @component('mail::panel') This is the panel content. @endcomponent #### 表格组件 表格组件允许你将 Markdown 表格转换成 HTML 表格。此组建接受 Markdown 表格作为其内容。列对齐支持默认的 Markdown 表格对齐语法: @component('mail::table') | Laravel | Table | Example | | ------------- |:-------------:| --------:| | Col 2 is | Centered | $10 | | Col 3 is | Right-Aligned | $20 | @endcomponent <a name="customizing-the-components"></a> ### 自定义组件 可以将所有 Markdown 邮件组件导出到自己的应用,用作自定义组件的模板。若要导出这些组件,使用带有 `laravel-mail` 资产标签的 `vendor:publish` Artisan 命令: php artisan vendor:publish --tag=laravel-mail 此命令将 Markdown 邮件组件导出到 `resources/views/vendor/mail` 目录。 `mail` 目录包含 `html` 和 `text` 子目录, 分别包含各自对应的可用组件描述。可以按照自己的意愿自定义这些组件。 #### 自定义 CSS 组建导出以后,`resources/views/vendor/mail/html/themes` 目录有一个 `default.css` 文件。可以自此文件中自定义 CSS,这些样式将自动内联到 Markdown 邮件消息的 HTML 表示中。 > {tip} 如果想为 Markdown 组件创建完整的新主题,可以在 `html/themes` 目录新建一个 CSS 文件,并修改 `mail` 配置文件的 `theme` 选项。 <a name="sending-mail"></a> ## 发送邮件 若要发送邮件,使用 `Mail` [facade](/docs/{{version}}/facades) 的 `to` 方法。 `to` 方法接受 邮件地址、用户实例或用户集合。如果传递一个对象或者对象集合,mailer 在设置收件人时将自动使用它们的 `email` 和 `name` 属性,因此请确保对象的这些属性可用。一旦制定了收件人,就可以将 mailable 类实例传递给 `send` 方法: <?php namespace App\Http\Controllers; use App\Order; use App\Mail\OrderShipped; use Illuminate\Http\Request; use Illuminate\Support\Facades\Mail; use App\Http\Controllers\Controller; class OrderController extends Controller { /** * 发送给定的订单。 * * @param Request $request * @param int $orderId * @return Response */ public function ship(Request $request, $orderId) { $order = Order::findOrFail($orderId); // 发送订单... Mail::to($request->user())->send(new OrderShipped($order)); } } 在发送消息时不止可以指定收件人。还可以通过链式调用「to」、「cc」、「bcc」一次性指定抄送和密送收件人: Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->send(new OrderShipped($order)); <a name="rendering-mailables"></a> ## 渲染 Mailable 有时可能希望捕获 mailable 的 HTML 内容,而不发送它。可以调用 mailable 的 `render` 方法实现此目的。此方法返回 mailable 渲染计算后的字符串: $invoice = App\Invoice::find(1); return (new App\Mail\InvoicePaid($invoice))->render(); <a name="previewing-mailables-in-the-browser"></a> ### 在浏览器中预览 Mailable 设计 mailable 模板时,像 Blade 模板一样在浏览器中预览和渲染 mailable 是很方便的。这种情况下,Laravel 允许你在路由闭包或控制其中直接返回任意 mailable。返回的 mailable将在浏览器中渲染和显示,你可以快速预览设计效果,而不需要将其发送到真实的邮件地址: Route::get('mailable', function () { $invoice = App\Invoice::find(1); return new App\Mail\InvoicePaid($invoice); }); <a name="queueing-mail"></a> ### 邮件队列 #### 将邮件消息加入队列 由于发送邮件消息可能大幅度延长应用的响应时间,许多开发者选择将邮件消息加入队列放在后台发送。Laravel 使用内置的 [统一队列 API](/docs/{{version}}/queues) 简化了这一工作。若要将邮件消息加入队列,可以在制定消息的接收者后,使用 `Mail` facade 的 `queue` 方法: Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->queue(new OrderShipped($order)); 此方法自动将作业推送到队列中以便消息在后台发送。使用此特性之前,需要 [配置队列](/docs/{{version}}/queues) : #### 延迟消息队列 想要延迟发送队列化的邮件消息,可以使用 `later` 方法。`later` 方法的第一个参数的第一个参数是标示消息何时发送的 `DateTime` 实例: $when = now()->addMinutes(10); Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->later($when, new OrderShipped($order)); #### 推送到指定队列 由于所有使用 `make:mail` 命令生成的 mailable 类都是用了 `Illuminate\Bus\Queueable` trait,因此你可以在任何 mailable 类实例上调用 `onQueue` 和 `onConnection` 方法来指定消息的连接和队列名: $message = (new OrderShipped($order)) ->onConnection('sqs') ->onQueue('emails'); Mail::to($request->user()) ->cc($moreUsers) ->bcc($evenMoreUsers) ->queue($message); #### 默认队列 如果一个 mailable 类总是要队列化,可以在此类上实现 `ShouldQueue` 契约。这样一来,即使你在发送时调用了 `send` 方法, mailable 也将被队列化: use Illuminate\Contracts\Queue\ShouldQueue; class OrderShipped extends Mailable implements ShouldQueue { // } <a name="localizing-mailables"></a> ## 本地化 Mailable Laravel 允许你使用有别于当前语言的区域设置发送 mailable,即使被加入到队列中也保留该区域设置。 为达到此目的, `Mail` facade 提供了 `locale` 方法设置目标语言。应用在格式化 mailable 是将切换到该区域设置,并在格式化完成后恢复到原来的区域设置: Mail::to($request->user())->locale('es')->send( new OrderShipped($order) ); ### 用户首选区域设置 有时候,应用存储每个用户的首选区域设置。通过在一个或多个模型上实现 `HasLocalePreference` 契约,可以通知 Laravel 再发送邮件时使用预存的区域设置: use Illuminate\Contracts\Translation\HasLocalePreference; class User extends Model implements HasLocalePreference { /** * 获取用户首选区域设置。 * * @return string */ public function preferredLocale() { return $this->locale; } } 一旦实现了此接口,Laravel 在向此模型发送 mailable 和通知时,将自动使用首选区域设置。因此在使用此接口时不需要调用 `locale` 方法: Mail::to($request->user())->send(new OrderShipped($order)); <a name="mail-and-local-development"></a> ## 邮件 & 本地开发 在开发发送邮件的应用时,你也许不想真的向实时邮件地址发送邮件。Laravel 为本地开发期间提供了几个 「禁用」真实发送的途径。 #### 日志驱动 `log` 邮件驱动采取将邮件消息写入日志取代发送邮件,已备查看。应用环境配置的更多消息,请查阅 [配置文档](/docs/{{version}}/configuration#environment-configuration)。 #### 通用配置 Laravel 为通过框架发送的邮件提供了指定常用收件人的其他解决方案。通过此方法,应用生成的邮件都将发送到指定地址,以取代发送消息时指定的真实地址。可以借助 `config/mail.php` 配置文件的 `to` 选项实现此目的: 'to' => [ 'address' => 'example@example.com', 'name' => 'Example' ], #### Mailtrap 最后,你可以使用 [Mailtrap](https://mailtrap.io) 服务和 `smtp` 驱动发送邮件消息到 「虚拟」邮箱,这样就可以在真实的邮件客户端查看邮件消息。此方法的好处是允许你在 Mailtrap 的消息阅览器中实际查看最终的邮件。 <a name="events"></a> ## 事件 Laravel 在处理邮件消息发送时触发两个事件。`MessageSending` 事件在消息发送前触发,`MessageSent` 事件则在消息发送后触发。切记,这些事件是在邮件被 *发送* 时触发,而不是在队列化的时候。可以在 `EventServiceProvider` 中注册此事件的侦听器: /** * 为应用映射事件侦听器。 * * @var array */ protected $listen = [ 'Illuminate\Mail\Events\MessageSending' => [ 'App\Listeners\LogSendingMessage', ], 'Illuminate\Mail\Events\MessageSent' => [ 'App\Listeners\LogSentMessage', ], ];