邮件
介绍
Laravel 提供了一个简洁、简单的 API,基于流行的 SwiftMailer 库,支持 SMTP、Mailgun、Postmark、SparkPost、Amazon SES 和 sendmail
驱动程序,让您可以快速开始通过本地或云服务发送邮件。
驱动程序先决条件
基于 API 的驱动程序如 Mailgun、SparkPost 和 Postmark 通常比 SMTP 服务器更简单、更快。如果可能,您应该使用这些驱动程序。所有 API 驱动程序都需要 Guzzle HTTP 库,可以通过 Composer 包管理器安装:
composer require guzzlehttp/guzzle
Mailgun 驱动程序
要使用 Mailgun 驱动程序,首先安装 Guzzle,然后在 config/mail.php
配置文件中将 driver
选项设置为 mailgun
。接下来,验证您的 config/services.php
配置文件包含以下选项:
'mailgun' => [
'domain' => 'your-mailgun-domain',
'secret' => 'your-mailgun-key',
],
如果您不使用 "US" Mailgun 区域,可以在 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 端点:
'sparkpost' => [
'secret' => 'your-sparkpost-key',
'options' => [
'endpoint' => 'https://api.eu.sparkpost.com/api/v1/transmissions',
],
],
SES 驱动程序
要使用 Amazon SES 驱动程序,您必须首先安装 Amazon AWS SDK for PHP。您可以通过在 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', // 例如 us-east-1
],
如果您需要在执行 SES SendRawEmail
请求时包含 其他选项,可以在 ses
配置中定义一个 options
数组:
'ses' => [
'key' => 'your-ses-key',
'secret' => 'your-ses-secret',
'region' => 'ses-region', // 例如 us-east-1
'options' => [
'ConfigurationSetName' => 'MyConfigurationSet',
'Tags' => [
[
'Name' => 'foo',
'Value' => 'bar',
],
],
],
],
生成邮件类
在 Laravel 中,应用程序发送的每种类型的电子邮件都表示为一个 "mailable" 类。这些类存储在 app/Mail
目录中。如果您在应用程序中没有看到此目录,不用担心,因为当您使用 make:mail
命令创建第一个邮件类时,它将为您生成:
php artisan make:mail OrderShipped
编写邮件类
所有邮件类的配置都在 build
方法中完成。在此方法中,您可以调用各种方法,如 from
、subject
、view
和 attach
,以配置电子邮件的展示和传递。
配置发件人
使用 from
方法
首先,让我们探讨如何配置电子邮件的发件人。换句话说,电子邮件将从谁那里发送。有两种方法可以配置发件人。首先,您可以在邮件类的 build
方法中使用 from
方法:
/**
* 构建消息。
*
* @return $this
*/
public function build()
{
return $this->from('example@example.com')
->view('emails.orders.shipped');
}
使用全局 from
地址
然而,如果您的应用程序为所有电子邮件使用相同的 "from" 地址,那么在每个生成的邮件类中调用 from
方法可能会变得繁琐。相反,您可以在 config/mail.php
配置文件中指定一个全局 "from" 地址。如果邮件类中没有指定其他 "from" 地址,将使用此地址:
'from' => ['address' => 'example@example.com', 'name' => 'App Name'],
此外,您可以在 config/mail.php
配置文件中定义一个全局 "reply_to" 地址:
'reply_to' => ['address' => 'example@example.com', 'name' => 'App Name'],
配置视图
在邮件类的 build
方法中,您可以使用 view
方法指定在渲染电子邮件内容时应使用哪个模板。由于每封电子邮件通常使用 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');
}
视图数据
通过公共属性
通常,您会希望将一些数据传递给视图,以便在渲染电子邮件的 HTML 时使用。有两种方法可以将数据提供给视图。首先,邮件类中定义的任何公共属性都将自动提供给视图。因此,例如,您可以将数据传递到邮件类的构造函数中,并将该数据设置为类中定义的公共属性:
<?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>
价格: {{ $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>
价格: {{ $orderPrice }}
</div>
附件
要向电子邮件添加附件,请在邮件类的 build
方法中使用 attach
方法。attach
方法接受文件的完整路径作为第一个参数:
/**
* 构建消息。
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file');
}
在将文件附加到消息时,您还可以通过将 array
作为第二个参数传递给 attach
方法来指定显示名称和/或 MIME 类型:
/**
* 构建消息。
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
从磁盘附加文件
如果您在 文件系统磁盘 上存储了一个文件,可以使用 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
方法接受原始数据字节作为第一个参数,文件名作为第二个参数,以及选项数组作为第三个参数:
/**
* 构建消息。
*
* @return $this
*/
public function build()
{
return $this->view('emails.orders.shipped')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
内联附件
将内联图像嵌入到电子邮件中通常很麻烦;然而,Laravel 提供了一种方便的方法来将图像附加到电子邮件中并检索适当的 CID。要嵌入内联图像,请在电子邮件模板中使用 $message
变量上的 embed
方法。Laravel 自动将 $message
变量提供给所有电子邮件模板,因此您无需手动传递它:
<body>
这里是一张图片:
<img src="{{ $message->embed($pathToImage) }}">
</body>
$message
变量在纯文本消息中不可用,因为纯文本消息不使用内联附件。
嵌入原始数据附件
如果您已经有一个要嵌入到电子邮件模板中的原始数据字符串,可以使用 $message
变量上的 embedData
方法:
<body>
这里是一张来自原始数据的图片:
<img src="{{ $message->embedData($data, $name) }}">
</body>
自定义 SwiftMailer 消息
Mailable
基类的 withSwiftMessage
方法允许您注册一个回调,该回调将在发送消息之前使用原始 SwiftMailer 消息实例调用。这为您提供了在消息发送之前自定义消息的机会:
/**
* 构建消息。
*
* @return $this
*/
public function build()
{
$this->view('emails.orders.shipped');
$this->withSwiftMessage(function ($message) {
$message->getHeaders()
->addTextHeader('Custom-Header', 'HeaderValue');
});
}
Markdown 邮件类
Markdown 邮件类消息允许您在邮件类中利用邮件通知的预构建模板和组件。由于消息是用 Markdown 编写的,Laravel 能够为消息渲染美观、响应式的 HTML 模板,同时自动生成纯文本副本。
生成 Markdown 邮件类
要生成带有相应 Markdown 模板的邮件类,可以使用 make:mail
Artisan 命令的 --markdown
选项:
php artisan make:mail OrderShipped --markdown=emails.orders.shipped
然后,在邮件类的 build
方法中配置邮件类时,调用 markdown
方法而不是 view
方法。markdown
方法接受 Markdown 模板的名称和一个可选的数据数组,以便提供给模板:
/**
* 构建消息。
*
* @return $this
*/
public function build()
{
return $this->from('example@example.com')
->markdown('emails.orders.shipped');
}
编写 Markdown 消息
Markdown 邮件类使用 Blade 组件和 Markdown 语法的组合,允许您轻松构建邮件消息,同时利用 Laravel 的预制组件:
@component('mail::message')
# 订单已发货
您的订单已发货!
@component('mail::button', ['url' => $url])
查看订单
@endcomponent
谢谢,<br>
{{ config('app.name') }}
@endcomponent
编写 Markdown 电子邮件时不要使用过多缩进。Markdown 解析器会将缩进内容渲染为代码块。
按钮组件
按钮组件渲染一个居中的按钮链接。该组件接受两个参数,一个 url
和一个可选的 color
。支持的颜色有 primary
、success
和 error
。您可以在消息中添加任意数量的按钮组件:
@component('mail::button', ['url' => $url, 'color' => 'success'])
查看订单
@endcomponent
面板组件
面板组件将给定的文本块渲染在一个面板中,该面板的背景颜色与消息的其余部分略有不同。这使您可以将注意力集中在给定的文本块上:
@component('mail::panel')
这是面板内容。
@endcomponent
表格组件
表格组件允许您将 Markdown 表格转换为 HTML 表格。该组件接受 Markdown 表格作为其内容。表格列对齐支持使用默认的 Markdown 表格对齐语法:
@component('mail::table')
| Laravel | 表格 | 示例 |
| ------------- |:-------------:| --------:|
| 列 2 是 | 居中 | $10 |
| 列 3 是 | 右对齐 | $20 |
@endcomponent
自定义组件
您可以将所有 Markdown 邮件组件导出到您自己的应用程序中进行自定义。要导出组件,请使用 vendor:publish
Artisan 命令发布 laravel-mail
资产标签:
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 表示中。
如果您想为 Laravel 的 Markdown 组件构建一个全新的主题,可以在 html/themes
目录中放置一个 CSS 文件。命名并保存您的 CSS 文件后,更新 mail
配置文件的 theme
选项以匹配新主题的名称。
要为单个邮件类自定义主题,可以将邮件类的 $theme
属性设置为发送该邮件类时应使用的主题名称。
发送邮件
要发送消息,请在 Mail
facade 上使用 to
方法。to
方法接受一个电子邮件地址、一个用户实例或一个用户集合。如果您传递一个对象或对象集合,邮件程序将自动使用它们的 email
和 name
属性来设置电子邮件收件人,因此请确保这些属性在您的对象上可用。一旦您指定了收件人,可以将邮件类实例传递给 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" 收件人。您可以在单个链式方法调用中自由设置 "to"、"cc" 和 "bcc" 收件人:
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->send(new OrderShipped($order));
渲染邮件类
有时您可能希望捕获邮件类的 HTML 内容而不发送它。为此,您可以调用邮件类的 render
方法。此方法将返回邮件类的评估内容作为字符串:
$invoice = App\Invoice::find(1);
return (new App\Mail\InvoicePaid($invoice))->render();
在浏览器中预览邮件类
在设计邮件类的模板时,可以方便地在浏览器中快速预览渲染的邮件类,就像典型的 Blade 模板一样。为此,Laravel 允许您直接从路由闭包或控制器返回任何邮件类。当返回邮件类时,它将被渲染并显示在浏览器中,允许您快速预览其设计,而无需将其发送到实际的电子邮件地址:
Route::get('mailable', function () {
$invoice = App\Invoice::find(1);
return new App\Mail\InvoicePaid($invoice);
});
队列邮件
队列邮件消息
由于发送电子邮件消息会显著延长应用程序的响应时间,许多开发人员选择将电子邮件消息排队以便在后台发送。Laravel 使用其内置的 统一队列 API 使这变得简单。要将邮件消息排队,请在指定消息的收件人后使用 Mail
facade 上的 queue
方法:
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue(new OrderShipped($order));
此方法将自动处理将作业推送到队列中,以便消息在后台发送。您需要在使用此功能之前 配置您的队列。
延迟消息队列
如果您希望延迟队列电子邮件消息的发送,可以使用 later
方法。作为其第一个参数,later
方法接受一个 DateTime
实例,指示消息应何时发送:
$when = now()->addMinutes(10);
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->later($when, new OrderShipped($order));
推送到特定队列
由于使用 make:mail
命令生成的所有邮件类都使用 Illuminate\Bus\Queueable
trait,您可以在任何邮件类实例上调用 onQueue
和 onConnection
方法,允许您为消息指定连接和队列名称:
$message = (new OrderShipped($order))
->onConnection('sqs')
->onQueue('emails');
Mail::to($request->user())
->cc($moreUsers)
->bcc($evenMoreUsers)
->queue($message);
默认队列
如果您有希望始终排队的邮件类,可以在类上实现 ShouldQueue
合约。现在,即使在发送邮件时调用 send
方法,由于实现了合约,邮件类仍将排队:
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderShipped extends Mailable implements ShouldQueue
{
//
}
本地化邮件类
Laravel 允许您以当前语言以外的语言发送邮件类,甚至在邮件排队时记住此语言。
为此,Mail
facade 提供了一个 locale
方法来设置所需的语言。应用程序将在格式化邮件类时切换到此语言,然后在格式化完成后恢复到先前的语言:
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 将在向模型发送邮件类和通知时自动使用首选语言。因此,在使用此接口时无需调用 locale
方法:
Mail::to($request->user())->send(new OrderShipped($order));
邮件与本地开发
在开发发送电子邮件的应用程序时,您可能不希望实际将电子邮件发送到真实的电子邮件地址。Laravel 提供了几种方法来在本地开发期间 "禁用" 实际发送电子邮件。
日志驱动程序
log
邮件驱动程序不会发送您的电子邮件,而是将所有电子邮件消息写入日志文件以供检查。有关按环境配置应用程序的更多信息,请查看 配置文档。
通用收件人
Laravel 提供的另一种解决方案是设置一个通用收件人,以接收框架发送的所有电子邮件。这样,应用程序生成的所有电子邮件将发送到特定地址,而不是发送消息时实际指定的地址。这可以通过 config/mail.php
配置文件中的 to
选项完成:
'to' => [
'address' => 'example@example.com',
'name' => 'Example'
],
Mailtrap
最后,您可以使用像 Mailtrap 这样的服务和 smtp
驱动程序将电子邮件消息发送到一个 "虚拟" 邮箱,您可以在真实的电子邮件客户端中查看它们。这种方法的好处是可以在 Mailtrap 的消息查看器中实际检查最终的电子邮件。
事件
在发送邮件消息的过程中,Laravel 会触发两个事件。MessageSending
事件在消息发送之前触发,而 MessageSent
事件在消息发送之后触发。请记住,这些事件是在邮件 发送 时触发的,而不是在邮件排队时触发的。您可以在 EventServiceProvider
中为此事件注册事件监听器:
/**
* 应用程序的事件监听器映射。
*
* @var array
*/
protected $listen = [
'Illuminate\Mail\Events\MessageSending' => [
'App\Listeners\LogSendingMessage',
],
'Illuminate\Mail\Events\MessageSent' => [
'App\Listeners\LogSentMessage',
],
];