郵件
簡介
發送電子郵件不必複雜。Laravel 提供了一個簡潔、簡單的電子郵件 API,由流行的 Symfony Mailer 組件驅動。Laravel 和 Symfony Mailer 提供了透過 SMTP、Mailgun、Postmark、Resend、Amazon SES 和 sendmail
發送電子郵件的驅動程式,讓您可以快速開始透過本地或基於雲端的服務發送郵件。
設定
Laravel 的電子郵件服務可以透過應用程式的 config/mail.php
設定檔進行設定。在此檔案中設定的每個郵件程式都可以有自己獨特的設定,甚至有自己獨特的「傳輸器」,讓您的應用程式可以使用不同的電子郵件服務來發送特定的電子郵件訊息。例如,您的應用程式可以使用 Postmark 發送交易電子郵件,同時使用 Amazon SES 發送大量電子郵件。
在您的 mail
設定檔中,您會找到一個 mailers
設定陣列。這個陣列包含 Laravel 支援的每個主要郵件驅動程式 / 傳輸器的範例設定條目,而 default
設定值決定了當您的應用程式需要發送電子郵件訊息時,預設將使用哪個郵件程式。
驅動程式 / 傳輸器先決條件
基於 API 的驅動程式(例如 Mailgun、Postmark、Resend 和 MailerSend)通常比透過 SMTP 伺服器發送郵件更簡單、更快速。在可能的情況下,我們建議您使用這些驅動程式之一。
Mailgun 驅動程式
要使用 Mailgun 驅動程式,請透過 Composer 安裝 Symfony 的 Mailgun Mailer 傳輸器
1composer require symfony/mailgun-mailer symfony/http-client
接下來,您需要在應用程式的 config/mail.php
設定檔中進行兩項變更。首先,將您的預設郵件程式設定為 mailgun
1'default' => env('MAIL_MAILER', 'mailgun'),
其次,將以下設定陣列添加到您的 mailers
陣列中
1'mailgun' => [2 'transport' => 'mailgun',3 // 'client' => [4 // 'timeout' => 5,5 // ],6],
設定應用程式的預設郵件程式後,將以下選項添加到您的 config/services.php
設定檔中
1'mailgun' => [2 'domain' => env('MAILGUN_DOMAIN'),3 'secret' => env('MAILGUN_SECRET'),4 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),5 'scheme' => 'https',6],
如果您沒有使用美國 Mailgun 區域,您可以在 services
設定檔中定義您區域的端點
1'mailgun' => [2 'domain' => env('MAILGUN_DOMAIN'),3 'secret' => env('MAILGUN_SECRET'),4 'endpoint' => env('MAILGUN_ENDPOINT', 'api.eu.mailgun.net'),5 'scheme' => 'https',6],
Postmark 驅動程式
要使用 Postmark 驅動程式,請透過 Composer 安裝 Symfony 的 Postmark Mailer 傳輸器
1composer require symfony/postmark-mailer symfony/http-client
接下來,將應用程式的 config/mail.php
設定檔中的 default
選項設定為 postmark
。設定應用程式的預設郵件程式後,請確保您的 config/services.php
設定檔包含以下選項
1'postmark' => [2 'token' => env('POSTMARK_TOKEN'),3],
如果您想指定給定郵件程式應使用的 Postmark 訊息流,您可以將 message_stream_id
設定選項添加到郵件程式的設定陣列中。此設定陣列可以在您的應用程式的 config/mail.php
設定檔中找到
1'postmark' => [2 'transport' => 'postmark',3 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),4 // 'client' => [5 // 'timeout' => 5,6 // ],7],
這樣您也可以設定具有不同訊息流的多個 Postmark 郵件程式。
Resend 驅動程式
要使用 Resend 驅動程式,請透過 Composer 安裝 Resend 的 PHP SDK
1composer require resend/resend-php
接下來,將應用程式的 config/mail.php
設定檔中的 default
選項設定為 resend
。設定應用程式的預設郵件程式後,請確保您的 config/services.php
設定檔包含以下選項
1'resend' => [2 'key' => env('RESEND_KEY'),3],
SES 驅動程式
要使用 Amazon SES 驅動程式,您必須先安裝適用於 PHP 的 Amazon AWS SDK。您可以透過 Composer 套件管理器安裝此函式庫
1composer require aws/aws-sdk-php
接下來,將 config/mail.php
設定檔中的 default
選項設定為 ses
,並驗證您的 config/services.php
設定檔是否包含以下選項
1'ses' => [2 'key' => env('AWS_ACCESS_KEY_ID'),3 'secret' => env('AWS_SECRET_ACCESS_KEY'),4 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),5],
若要透過工作階段令牌使用 AWS 臨時憑證,您可以將 token
金鑰新增至應用程式的 SES 設定
1'ses' => [2 'key' => env('AWS_ACCESS_KEY_ID'),3 'secret' => env('AWS_SECRET_ACCESS_KEY'),4 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),5 'token' => env('AWS_SESSION_TOKEN'),6],
若要與 SES 的 訂閱管理功能 互動,您可以在 headers
郵件訊息的方法傳回的陣列中傳回 X-Ses-List-Management-Options
標頭
1/** 2 * Get the message headers. 3 */ 4public function headers(): Headers 5{ 6 return new Headers( 7 text: [ 8 'X-Ses-List-Management-Options' => 'contactListName=MyContactList;topicName=MyTopic', 9 ],10 );11}
如果您想定義 Laravel 在發送電子郵件時應傳遞給 AWS SDK 的 SendEmail
方法的其他選項,您可以在 ses
設定中定義 options
陣列
1'ses' => [ 2 'key' => env('AWS_ACCESS_KEY_ID'), 3 'secret' => env('AWS_SECRET_ACCESS_KEY'), 4 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 5 'options' => [ 6 'ConfigurationSetName' => 'MyConfigurationSet', 7 'EmailTags' => [ 8 ['Name' => 'foo', 'Value' => 'bar'], 9 ],10 ],11],
MailerSend 驅動程式
MailerSend 是一種交易電子郵件和 SMS 服務,為 Laravel 維護了自己的基於 API 的郵件驅動程式。包含驅動程式的套件可以透過 Composer 套件管理器安裝
1composer require mailersend/laravel-driver
安裝套件後,將 MAILERSEND_API_KEY
環境變數新增到應用程式的 .env
檔案。此外,MAIL_MAILER
環境變數應定義為 mailersend
1MAIL_MAILER=mailersend3MAIL_FROM_NAME="App Name"4 5MAILERSEND_API_KEY=your-api-key
最後,將 MailerSend 新增到應用程式的 config/mail.php
設定檔中的 mailers
陣列
1'mailersend' => [2 'transport' => 'mailersend',3],
若要深入瞭解 MailerSend,包括如何使用託管範本,請參閱 MailerSend 驅動程式文件。
容錯移轉設定
有時,您設定用於發送應用程式郵件的外部服務可能會關閉。在這些情況下,定義一個或多個備份郵件傳遞設定可能會很有用,以便在您的主要傳遞驅動程式關閉時使用。
為了實現這一點,您應該在應用程式的 mail
設定檔中定義一個使用 failover
傳輸器的郵件程式。應用程式的 failover
郵件程式的設定陣列應包含一個 mailers
陣列,其中引用了為傳遞選擇已設定郵件程式的順序
1'mailers' => [ 2 'failover' => [ 3 'transport' => 'failover', 4 'mailers' => [ 5 'postmark', 6 'mailgun', 7 'sendmail', 8 ], 9 ],10 11 // ...12],
定義容錯移轉郵件程式後,您應該將此郵件程式設定為應用程式使用的預設郵件程式,方法是在應用程式的 mail
設定檔中將其名稱指定為 default
設定金鑰的值
1'default' => env('MAIL_MAILER', 'failover'),
循環配置
roundrobin
傳輸器允許您將郵件工作負載分佈到多個郵件程式。若要開始使用,請在應用程式的 mail
設定檔中定義一個使用 roundrobin
傳輸器的郵件程式。應用程式的 roundrobin
郵件程式的設定陣列應包含一個 mailers
陣列,其中引用了應使用哪些已設定的郵件程式進行傳遞
1'mailers' => [ 2 'roundrobin' => [ 3 'transport' => 'roundrobin', 4 'mailers' => [ 5 'ses', 6 'postmark', 7 ], 8 ], 9 10 // ...11],
定義循環配置郵件程式後,您應該將此郵件程式設定為應用程式使用的預設郵件程式,方法是在應用程式的 mail
設定檔中將其名稱指定為 default
設定金鑰的值
1'default' => env('MAIL_MAILER', 'roundrobin'),
循環配置傳輸器從已設定的郵件程式清單中選擇一個隨機郵件程式,然後為每個後續電子郵件切換到下一個可用的郵件程式。與有助於實現高可用性的 failover
傳輸器相比,roundrobin
傳輸器提供負載平衡。
產生可郵寄類別
在建置 Laravel 應用程式時,應用程式發送的每種電子郵件類型都表示為「可郵寄」類別。這些類別儲存在 app/Mail
目錄中。如果您在應用程式中看不到此目錄,請別擔心,因為當您使用 make:mail
Artisan 命令建立第一個可郵寄類別時,將會為您產生該目錄
1php artisan make:mail OrderShipped
編寫可郵寄類別
產生可郵寄類別後,開啟它,以便我們可以探索其內容。可郵寄類別設定在多個方法中完成,包括 envelope
、content
和 attachments
方法。
envelope
方法傳回一個 Illuminate\Mail\Mailables\Envelope
物件,該物件定義了郵件的主旨,有時還定義了收件者。content
方法傳回一個 Illuminate\Mail\Mailables\Content
物件,該物件定義了將用於產生郵件內容的 Blade 範本。
設定寄件者
使用 Envelope
首先,讓我們探索設定電子郵件的寄件者。或者,換句話說,電子郵件將「來自」誰。有兩種方法可以設定寄件者。首先,您可以在郵件的 envelope 上指定「寄件者」地址
1use Illuminate\Mail\Mailables\Address; 2use Illuminate\Mail\Mailables\Envelope; 3 4/** 5 * Get the message envelope. 6 */ 7public function envelope(): Envelope 8{ 9 return new Envelope(11 subject: 'Order Shipped',12 );13}
如果您願意,您也可以指定 replyTo
地址
1return new Envelope(3 replyTo: [5 ],6 subject: 'Order Shipped',7);
使用全域 from
地址
但是,如果您的應用程式對其所有電子郵件使用相同的「寄件者」地址,則將其添加到您產生的每個可郵寄類別可能會變得繁瑣。相反,您可以在 config/mail.php
設定檔中指定全域「寄件者」地址。如果在可郵寄類別中未指定其他「寄件者」地址,則將使用此地址
1'from' => [3 'name' => env('MAIL_FROM_NAME', 'Example'),4],
此外,您可以在 config/mail.php
設定檔中定義全域「reply_to」地址
設定視圖
在可郵寄類別的 content
方法中,您可以定義 view
,或在渲染電子郵件內容時應使用的範本。由於每封電子郵件通常都使用 Blade 範本 來渲染其內容,因此在建置電子郵件的 HTML 時,您擁有 Blade 範本引擎的全部功能和便利性
1/**2 * Get the message content definition.3 */4public function content(): Content5{6 return new Content(7 view: 'mail.orders.shipped',8 );9}
您可能希望建立一個 resources/views/emails
目錄來存放所有電子郵件範本;但是,您可以將它們自由放置在 resources/views
目錄中的任何位置。
純文字電子郵件
如果您想定義電子郵件的純文字版本,您可以在建立郵件的 Content
定義時指定純文字範本。與 view
參數類似,text
參數應該是一個範本名稱,它將用於渲染電子郵件的內容。您可以自由定義郵件的 HTML 和純文字版本
1/** 2 * Get the message content definition. 3 */ 4public function content(): Content 5{ 6 return new Content( 7 view: 'mail.orders.shipped', 8 text: 'mail.orders.shipped-text' 9 );10}
為了清楚起見,html
參數可以用作 view
參數的別名
1return new Content(2 html: 'mail.orders.shipped',3 text: 'mail.orders.shipped-text'4);
視圖資料
透過公開屬性
通常,您會想要將一些資料傳遞到您的視圖,以便在渲染電子郵件的 HTML 時使用。有兩種方法可以使資料在您的視圖中可用。首先,在您的可郵寄類別上定義的任何公開屬性都將自動在視圖中可用。因此,例如,您可以將資料傳遞到您的可郵寄類別的建構函式中,並將該資料設定為類別上定義的公開屬性
1<?php 2 3namespace App\Mail; 4 5use App\Models\Order; 6use Illuminate\Bus\Queueable; 7use Illuminate\Mail\Mailable; 8use Illuminate\Mail\Mailables\Content; 9use Illuminate\Queue\SerializesModels;10 11class OrderShipped extends Mailable12{13 use Queueable, SerializesModels;14 15 /**16 * Create a new message instance.17 */18 public function __construct(19 public Order $order,20 ) {}21 22 /**23 * Get the message content definition.24 */25 public function content(): Content26 {27 return new Content(28 view: 'mail.orders.shipped',29 );30 }31}
一旦資料設定為公開屬性,它將自動在您的視圖中可用,因此您可以像存取 Blade 範本中的任何其他資料一樣存取它
1<div>2 Price: {{ $order->price }}3</div>
透過 with
參數
如果您想在電子郵件的資料發送到範本之前自訂其格式,您可以透過 Content
定義的 with
參數手動將資料傳遞到視圖。通常,您仍然會透過可郵寄類別的建構函式傳遞資料;但是,您應該將此資料設定為 protected
或 private
屬性,以便資料不會自動在範本中可用
1<?php 2 3namespace App\Mail; 4 5use App\Models\Order; 6use Illuminate\Bus\Queueable; 7use Illuminate\Mail\Mailable; 8use Illuminate\Mail\Mailables\Content; 9use Illuminate\Queue\SerializesModels;10 11class OrderShipped extends Mailable12{13 use Queueable, SerializesModels;14 15 /**16 * Create a new message instance.17 */18 public function __construct(19 protected Order $order,20 ) {}21 22 /**23 * Get the message content definition.24 */25 public function content(): Content26 {27 return new Content(28 view: 'mail.orders.shipped',29 with: [30 'orderName' => $this->order->name,31 'orderPrice' => $this->order->price,32 ],33 );34 }35}
一旦資料傳遞到 with
方法,它將自動在您的視圖中可用,因此您可以像存取 Blade 範本中的任何其他資料一樣存取它
1<div>2 Price: {{ $orderPrice }}3</div>
附件
若要將附件新增到電子郵件,您需要將附件新增到郵件的 attachments
方法傳回的陣列中。首先,您可以透過提供檔案路徑到 Attachment
類別提供的 fromPath
方法來新增附件
1use Illuminate\Mail\Mailables\Attachment; 2 3/** 4 * Get the attachments for the message. 5 * 6 * @return array<int, \Illuminate\Mail\Mailables\Attachment> 7 */ 8public function attachments(): array 9{10 return [11 Attachment::fromPath('/path/to/file'),12 ];13}
將檔案附加到郵件時,您也可以使用 as
和 withMime
方法指定附件的顯示名稱和 / 或 MIME 類型
1/** 2 * Get the attachments for the message. 3 * 4 * @return array<int, \Illuminate\Mail\Mailables\Attachment> 5 */ 6public function attachments(): array 7{ 8 return [ 9 Attachment::fromPath('/path/to/file')10 ->as('name.pdf')11 ->withMime('application/pdf'),12 ];13}
從磁碟附加檔案
如果您已將檔案儲存在您的 檔案系統磁碟之一,則可以使用 fromStorage
附件方法將其附加到電子郵件
1/** 2 * Get the attachments for the message. 3 * 4 * @return array<int, \Illuminate\Mail\Mailables\Attachment> 5 */ 6public function attachments(): array 7{ 8 return [ 9 Attachment::fromStorage('/path/to/file'),10 ];11}
當然,您也可以指定附件的名稱和 MIME 類型
1/** 2 * Get the attachments for the message. 3 * 4 * @return array<int, \Illuminate\Mail\Mailables\Attachment> 5 */ 6public function attachments(): array 7{ 8 return [ 9 Attachment::fromStorage('/path/to/file')10 ->as('name.pdf')11 ->withMime('application/pdf'),12 ];13}
如果您需要指定預設磁碟以外的儲存磁碟,則可以使用 fromStorageDisk
方法
1/** 2 * Get the attachments for the message. 3 * 4 * @return array<int, \Illuminate\Mail\Mailables\Attachment> 5 */ 6public function attachments(): array 7{ 8 return [ 9 Attachment::fromStorageDisk('s3', '/path/to/file')10 ->as('name.pdf')11 ->withMime('application/pdf'),12 ];13}
原始資料附件
fromData
附件方法可用於將原始位元組字串附加為附件。例如,如果您在記憶體中產生了 PDF,並希望將其附加到電子郵件,而無需將其寫入磁碟,則可以使用此方法。fromData
方法接受一個閉包,該閉包解析原始資料位元組以及應分配給附件的名稱
1/** 2 * Get the attachments for the message. 3 * 4 * @return array<int, \Illuminate\Mail\Mailables\Attachment> 5 */ 6public function attachments(): array 7{ 8 return [ 9 Attachment::fromData(fn () => $this->pdf, 'Report.pdf')10 ->withMime('application/pdf'),11 ];12}
內嵌附件
將內嵌圖片嵌入到您的電子郵件中通常很麻煩;但是,Laravel 提供了一種將圖片附加到電子郵件的便捷方法。若要嵌入內嵌圖片,請在電子郵件範本中使用 $message
變數上的 embed
方法。Laravel 會自動使 $message
變數在您的所有電子郵件範本中可用,因此您不必擔心手動傳遞它
1<body>2 Here is an image:3 4 <img src="{{ $message->embed($pathToImage) }}">5</body>
$message
變數在純文字訊息範本中不可用,因為純文字訊息不使用內嵌附件。
嵌入原始資料附件
如果您已經有想要嵌入到電子郵件範本中的原始圖片資料字串,則可以在 $message
變數上呼叫 embedData
方法。呼叫 embedData
方法時,您需要提供應分配給嵌入圖片的檔案名稱
1<body>2 Here is an image from raw data:3 4 <img src="{{ $message->embedData($data, 'example-image.jpg') }}">5</body>
可附加物件
雖然透過簡單字串路徑將檔案附加到訊息通常就足夠了,但在許多情況下,應用程式中的可附加實體由類別表示。例如,如果您的應用程式正在將照片附加到訊息,則您的應用程式也可能有一個 Photo
模型來表示該照片。在這種情況下,簡單地將 Photo
模型傳遞給 attach
方法不是更方便嗎?可附加物件允許您這樣做。
若要開始使用,請在將附加到訊息的物件上實作 Illuminate\Contracts\Mail\Attachable
介面。此介面指示您的類別定義一個 toMailAttachment
方法,該方法傳回 Illuminate\Mail\Attachment
實例
1<?php 2 3namespace App\Models; 4 5use Illuminate\Contracts\Mail\Attachable; 6use Illuminate\Database\Eloquent\Model; 7use Illuminate\Mail\Attachment; 8 9class Photo extends Model implements Attachable10{11 /**12 * Get the attachable representation of the model.13 */14 public function toMailAttachment(): Attachment15 {16 return Attachment::fromPath('/path/to/file');17 }18}
定義可附加物件後,您可以在建置電子郵件訊息時從 attachments
方法傳回該物件的實例
1/**2 * Get the attachments for the message.3 *4 * @return array<int, \Illuminate\Mail\Mailables\Attachment>5 */6public function attachments(): array7{8 return [$this->photo];9}
當然,附件資料可以儲存在遠端檔案儲存服務(例如 Amazon S3)上。因此,Laravel 也允許您從儲存在應用程式的 檔案系統磁碟之一上的資料產生附件實例
1// Create an attachment from a file on your default disk...2return Attachment::fromStorage($this->path);3 4// Create an attachment from a file on a specific disk...5return Attachment::fromStorageDisk('backblaze', $this->path);
此外,您可以透過記憶體中的資料建立附件實例。若要完成此操作,請為 fromData
方法提供一個閉包。閉包應傳回表示附件的原始資料
1return Attachment::fromData(fn () => $this->content, 'Photo Name');
Laravel 還提供了其他方法,您可以使用這些方法來自訂附件。例如,您可以使用 as
和 withMime
方法來自訂檔案的名稱和 MIME 類型
1return Attachment::fromPath('/path/to/file')2 ->as('Photo Name')3 ->withMime('image/jpeg');
標頭
有時您可能需要將其他標頭附加到外發訊息。例如,您可能需要設定自訂 Message-Id
或其他任意文字標頭。
若要完成此操作,請在您的可郵寄類別上定義 headers
方法。headers
方法應傳回 Illuminate\Mail\Mailables\Headers
實例。此類別接受 messageId
、references
和 text
參數。當然,您可能只需要為您的特定訊息提供所需的參數
1use Illuminate\Mail\Mailables\Headers; 2 3/** 4 * Get the message headers. 5 */ 6public function headers(): Headers 7{ 8 return new Headers(11 text: [12 'X-Custom-Header' => 'Custom Value',13 ],14 );15}
標籤和元數據
某些第三方電子郵件提供者(例如 Mailgun 和 Postmark)支援訊息「標籤」和「元數據」,可用於群組和追蹤您的應用程式發送的電子郵件。您可以透過 Envelope
定義將標籤和元數據添加到電子郵件訊息
1use Illuminate\Mail\Mailables\Envelope; 2 3/** 4 * Get the message envelope. 5 * 6 * @return \Illuminate\Mail\Mailables\Envelope 7 */ 8public function envelope(): Envelope 9{10 return new Envelope(11 subject: 'Order Shipped',12 tags: ['shipment'],13 metadata: [14 'order_id' => $this->order->id,15 ],16 );17}
如果您的應用程式使用 Mailgun 驅動程式,您可以查閱 Mailgun 的文件以取得有關 標籤 和 元數據 的更多資訊。同樣,也可以查閱 Postmark 文件以取得有關他們對 標籤 和 元數據 的支援的更多資訊。
如果您的應用程式使用 Amazon SES 發送電子郵件,則應使用 metadata
方法將 SES「標籤」附加到訊息。
自訂 Symfony 訊息
Laravel 的郵件功能由 Symfony Mailer 提供支援。Laravel 允許您註冊自訂回呼,這些回呼將在發送訊息之前使用 Symfony Message 實例調用。這讓您有機會在發送訊息之前深度自訂訊息。若要完成此操作,請在您的 Envelope
定義上定義 using
參數
1use Illuminate\Mail\Mailables\Envelope; 2use Symfony\Component\Mime\Email; 3 4/** 5 * Get the message envelope. 6 */ 7public function envelope(): Envelope 8{ 9 return new Envelope(10 subject: 'Order Shipped',11 using: [12 function (Email $message) {13 // ...14 },15 ]16 );17}
Markdown 可郵寄類別
Markdown 可郵寄訊息允許您利用 郵件通知 的預先建置的範本和組件在您的可郵寄類別中使用。由於訊息是用 Markdown 寫成的,因此 Laravel 能夠為訊息渲染美觀、響應迅速的 HTML 範本,同時自動產生純文字副本。
產生 Markdown 可郵寄類別
若要產生具有對應 Markdown 範本的可郵寄類別,您可以使用 make:mail
Artisan 命令的 --markdown
選項
1php artisan make:mail OrderShipped --markdown=mail.orders.shipped
然後,在設定可郵寄類別 Content
定義在其 content
方法中時,請使用 markdown
參數而不是 view
參數
1use Illuminate\Mail\Mailables\Content; 2 3/** 4 * Get the message content definition. 5 */ 6public function content(): Content 7{ 8 return new Content( 9 markdown: 'mail.orders.shipped',10 with: [11 'url' => $this->orderUrl,12 ],13 );14}
編寫 Markdown 訊息
Markdown 可郵寄類別使用 Blade 組件和 Markdown 語法的組合,讓您可以輕鬆建構郵件訊息,同時利用 Laravel 預先建置的電子郵件 UI 組件
1<x-mail::message> 2# Order Shipped 3 4Your order has been shipped! 5 6<x-mail::button :url="$url"> 7View Order 8</x-mail::button> 9 10Thanks,<br>11{{ config('app.name') }}12</x-mail::message>
編寫 Markdown 電子郵件時,請勿使用過多的縮排。根據 Markdown 標準,Markdown 解析器會將縮排內容渲染為程式碼區塊。
按鈕組件
按鈕組件渲染居中的按鈕連結。該組件接受兩個參數,一個 url
和一個可選的 color
。支援的顏色為 primary
、success
和 error
。您可以根據需要向訊息新增任意數量的按鈕組件
1<x-mail::button :url="$url" color="success">2View Order3</x-mail::button>
面板組件
面板組件在面板中渲染給定的文字區塊,面板的背景顏色與訊息的其餘部分略有不同。這讓您可以將注意力吸引到給定的文字區塊
1<x-mail::panel>2This is the panel content.3</x-mail::panel>
表格組件
表格組件允許您將 Markdown 表格轉換為 HTML 表格。該組件接受 Markdown 表格作為其內容。使用預設 Markdown 表格對齊語法支援表格欄位對齊
1<x-mail::table>2| Laravel | Table | Example |3| ------------- | :-----------: | ------------: |4| Col 2 is | Centered | $10 |5| Col 3 is | Right-Aligned | $20 |6</x-mail::table>
自訂組件
您可以匯出所有 Markdown 郵件組件到您自己的應用程式以進行自訂。若要匯出組件,請使用 vendor:publish
Artisan 命令發佈 laravel-mail
資源標籤
1php 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 表示形式中的內嵌 CSS 樣式。
如果您想為 Laravel 的 Markdown 組件建置全新的主題,您可以將 CSS 檔案放在 html/themes
目錄中。在命名並儲存 CSS 檔案後,更新應用程式的 config/mail.php
設定檔的 theme
選項以符合您的新主題的名稱。
若要自訂個別可郵寄類別的主題,您可以將可郵寄類別的 $theme
屬性設定為發送該可郵寄類別時應使用的主題的名稱。
發送郵件
若要發送訊息,請使用 Mail
facade 上的 to
方法。to
方法接受電子郵件地址、使用者實例或使用者集合。如果您傳遞物件或物件集合,郵件程式將在確定電子郵件的收件者時自動使用其 email
和 name
屬性,因此請確保這些屬性在您的物件上可用。指定收件者後,您可以將可郵寄類別的實例傳遞給 send
方法
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Mail\OrderShipped; 7use App\Models\Order; 8use Illuminate\Http\RedirectResponse; 9use Illuminate\Http\Request;10use Illuminate\Support\Facades\Mail;11 12class OrderShipmentController extends Controller13{14 /**15 * Ship the given order.16 */17 public function store(Request $request): RedirectResponse18 {19 $order = Order::findOrFail($request->order_id);20 21 // Ship the order...22 23 Mail::to($request->user())->send(new OrderShipped($order));24 25 return redirect('/orders');26 }27}
您不僅限於在發送訊息時僅指定「收件者」。您可以自由地透過鏈接各自的方法來設定「收件者」、「副本」和「密件副本」收件者
1Mail::to($request->user())2 ->cc($moreUsers)3 ->bcc($evenMoreUsers)4 ->send(new OrderShipped($order));
迴圈處理收件者
有時,您可能需要透過迭代收件者/電子郵件地址陣列,將郵件發送給收件者列表。但是,由於 to
方法會將電子郵件地址附加到郵件的收件者列表中,因此每次迴圈迭代都會向每個先前的收件者發送另一封電子郵件。因此,您應始終為每位收件者重新建立郵件實例。
2 Mail::to($recipient)->send(new OrderShipped($order));3}
透過特定郵件程式發送郵件
預設情況下,Laravel 將使用在應用程式的 mail
設定檔中設定為 default
郵件程式的郵件程式發送電子郵件。但是,您可以使用 mailer
方法,以使用特定的郵件程式設定發送訊息。
1Mail::mailer('postmark')2 ->to($request->user())3 ->send(new OrderShipped($order));
佇列郵件
佇列郵件訊息
由於發送電子郵件訊息可能會對應用程式的回應時間產生負面影響,因此許多開發人員選擇將電子郵件訊息加入佇列以在背景發送。Laravel 透過其內建的 統一佇列 API,讓此操作變得容易。若要將郵件訊息加入佇列,請在指定訊息的收件者後,使用 Mail
facade 上的 queue
方法。
1Mail::to($request->user())2 ->cc($moreUsers)3 ->bcc($evenMoreUsers)4 ->queue(new OrderShipped($order));
此方法將自動處理將任務推送到佇列,以便在背景發送訊息。您需要先設定您的佇列,才能使用此功能。
延遲訊息佇列
如果您希望延遲佇列電子郵件訊息的傳遞,可以使用 later
方法。later
方法的第一個引數接受一個 DateTime
實例,指示應何時發送訊息。
1Mail::to($request->user())2 ->cc($moreUsers)3 ->bcc($evenMoreUsers)4 ->later(now()->addMinutes(10), new OrderShipped($order));
推送到特定佇列
由於所有使用 make:mail
命令產生的可郵件類別都使用了 Illuminate\Bus\Queueable
特性,因此您可以在任何可郵件類別實例上呼叫 onQueue
和 onConnection
方法,讓您可以為訊息指定連線和佇列名稱。
1$message = (new OrderShipped($order))2 ->onConnection('sqs')3 ->onQueue('emails');4 5Mail::to($request->user())6 ->cc($moreUsers)7 ->bcc($evenMoreUsers)8 ->queue($message);
預設佇列
如果您有希望始終加入佇列的可郵件類別,您可以在該類別上實作 ShouldQueue
契約。現在,即使您在郵寄時呼叫 send
方法,可郵件仍將加入佇列,因為它實作了該契約。
1use Illuminate\Contracts\Queue\ShouldQueue;2 3class OrderShipped extends Mailable implements ShouldQueue4{5 // ...6}
佇列郵件和資料庫交易
當佇列郵件在資料庫交易中被分派時,它們可能會在資料庫交易提交之前被佇列處理。當這種情況發生時,您在資料庫交易期間對模型或資料庫記錄所做的任何更新可能尚未反映在資料庫中。此外,在交易中建立的任何模型或資料庫記錄可能不存在於資料庫中。如果您的可郵件依賴於這些模型,則在處理發送佇列郵件的任務時可能會發生意外錯誤。
如果您的佇列連線的 after_commit
設定選項設定為 false
,您仍然可以透過在發送郵件訊息時呼叫 afterCommit
方法,來指示特定的佇列郵件應在所有開啟的資料庫交易提交後分派。
1Mail::to($request->user())->send(2 (new OrderShipped($order))->afterCommit()3);
或者,您可以從可郵件的建構子中呼叫 afterCommit
方法。
1<?php 2 3namespace App\Mail; 4 5use Illuminate\Bus\Queueable; 6use Illuminate\Contracts\Queue\ShouldQueue; 7use Illuminate\Mail\Mailable; 8use Illuminate\Queue\SerializesModels; 9 10class OrderShipped extends Mailable implements ShouldQueue11{12 use Queueable, SerializesModels;13 14 /**15 * Create a new message instance.16 */17 public function __construct()18 {19 $this->afterCommit();20 }21}
若要深入了解如何解決這些問題,請查看有關佇列任務和資料庫交易的文件。
渲染可郵寄類別
有時您可能希望在不發送郵件的情況下,擷取可郵件的 HTML 內容。若要完成此操作,您可以呼叫可郵件的 render
方法。此方法將以字串形式傳回可郵件的已評估 HTML 內容。
1use App\Mail\InvoicePaid;2use App\Models\Invoice;3 4$invoice = Invoice::find(1);5 6return (new InvoicePaid($invoice))->render();
在瀏覽器中預覽可郵寄類別
設計可郵件的範本時,快速在瀏覽器中預覽呈現的可郵件(如典型的 Blade 範本)非常方便。因此,Laravel 允許您直接從路由閉包或控制器傳回任何可郵件。當傳回可郵件時,它將在瀏覽器中呈現和顯示,讓您可以快速預覽其設計,而無需將其發送到實際的電子郵件地址。
1Route::get('/mailable', function () {2 $invoice = App\Models\Invoice::find(1);3 4 return new App\Mail\InvoicePaid($invoice);5});
本地化可郵寄類別
Laravel 允許您以請求目前語言環境以外的語言環境發送郵件,即使郵件已加入佇列,也會記住此語言環境。
為了完成此操作,Mail
facade 提供了 locale
方法來設定所需的語言。當評估可郵件的範本時,應用程式將變更為此語言環境,然後在評估完成後還原為先前的語言環境。
1Mail::to($request->user())->locale('es')->send(2 new OrderShipped($order)3);
使用者偏好的語言環境
有時,應用程式會儲存每個使用者偏好的語言環境。透過在您的一個或多個模型上實作 HasLocalePreference
契約,您可以指示 Laravel 在發送郵件時使用此儲存的語言環境。
1use Illuminate\Contracts\Translation\HasLocalePreference; 2 3class User extends Model implements HasLocalePreference 4{ 5 /** 6 * Get the user's preferred locale. 7 */ 8 public function preferredLocale(): string 9 {10 return $this->locale;11 }12}
一旦您實作了介面,Laravel 將在向模型發送郵件和通知時自動使用偏好的語言環境。因此,在使用此介面時,無需呼叫 locale
方法。
1Mail::to($request->user())->send(new OrderShipped($order));
測試
測試可郵寄類別內容
Laravel 提供了多種方法來檢查您的可郵件結構。此外,Laravel 還提供了幾種方便的方法來測試您的可郵件是否包含您期望的內容。這些方法包括:assertSeeInHtml
、assertDontSeeInHtml
、assertSeeInOrderInHtml
、assertSeeInText
、assertDontSeeInText
、assertSeeInOrderInText
、assertHasAttachment
、assertHasAttachedData
、assertHasAttachmentFromStorage
和 assertHasAttachmentFromStorageDisk
。
正如您可能預期的那樣,「HTML」斷言會斷言可郵件的 HTML 版本包含給定的字串,而「text」斷言會斷言可郵件的純文字版本包含給定的字串。
1use App\Mail\InvoicePaid; 2use App\Models\User; 3 4test('mailable content', function () { 5 $user = User::factory()->create(); 6 7 $mailable = new InvoicePaid($user); 8 14 $mailable->assertHasSubject('Invoice Paid');15 $mailable->assertHasTag('example-tag');16 $mailable->assertHasMetadata('key', 'value');17 18 $mailable->assertSeeInHtml($user->email);19 $mailable->assertSeeInHtml('Invoice Paid');20 $mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);21 22 $mailable->assertSeeInText($user->email);23 $mailable->assertSeeInOrderInText(['Invoice Paid', 'Thanks']);24 25 $mailable->assertHasAttachment('/path/to/file');26 $mailable->assertHasAttachment(Attachment::fromPath('/path/to/file'));27 $mailable->assertHasAttachedData($pdfData, 'name.pdf', ['mime' => 'application/pdf']);28 $mailable->assertHasAttachmentFromStorage('/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);29 $mailable->assertHasAttachmentFromStorageDisk('s3', '/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);30});
1use App\Mail\InvoicePaid; 2use App\Models\User; 3 4public function test_mailable_content(): void 5{ 6 $user = User::factory()->create(); 7 8 $mailable = new InvoicePaid($user); 9 15 $mailable->assertHasSubject('Invoice Paid');16 $mailable->assertHasTag('example-tag');17 $mailable->assertHasMetadata('key', 'value');18 19 $mailable->assertSeeInHtml($user->email);20 $mailable->assertSeeInHtml('Invoice Paid');21 $mailable->assertSeeInOrderInHtml(['Invoice Paid', 'Thanks']);22 23 $mailable->assertSeeInText($user->email);24 $mailable->assertSeeInOrderInText(['Invoice Paid', 'Thanks']);25 26 $mailable->assertHasAttachment('/path/to/file');27 $mailable->assertHasAttachment(Attachment::fromPath('/path/to/file'));28 $mailable->assertHasAttachedData($pdfData, 'name.pdf', ['mime' => 'application/pdf']);29 $mailable->assertHasAttachmentFromStorage('/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);30 $mailable->assertHasAttachmentFromStorageDisk('s3', '/path/to/file', 'name.pdf', ['mime' => 'application/pdf']);31}
測試可郵寄類別發送
我們建議您將可郵件的內容測試與斷言特定可郵件已「發送」給特定使用者的測試分開進行。通常,可郵件的內容與您正在測試的程式碼無關,並且只需斷言 Laravel 已被指示發送給定的可郵件就足夠了。
您可以使用 Mail
facade 的 fake
方法來防止發送郵件。在呼叫 Mail
facade 的 fake
方法後,您可以斷言可郵件已被指示發送給使用者,甚至可以檢查可郵件接收到的資料。
1<?php 2 3use App\Mail\OrderShipped; 4use Illuminate\Support\Facades\Mail; 5 6test('orders can be shipped', function () { 7 Mail::fake(); 8 9 // Perform order shipping...10 11 // Assert that no mailables were sent...12 Mail::assertNothingSent();13 14 // Assert that a mailable was sent...15 Mail::assertSent(OrderShipped::class);16 17 // Assert a mailable was sent twice...18 Mail::assertSent(OrderShipped::class, 2);19 20 // Assert a mailable was sent to an email address...22 23 // Assert a mailable was sent to multiple email addresses...25 26 // Assert a mailable was not sent...27 Mail::assertNotSent(AnotherMailable::class);28 29 // Assert 3 total mailables were sent...30 Mail::assertSentCount(3);31});
1<?php 2 3namespace Tests\Feature; 4 5use App\Mail\OrderShipped; 6use Illuminate\Support\Facades\Mail; 7use Tests\TestCase; 8 9class ExampleTest extends TestCase10{11 public function test_orders_can_be_shipped(): void12 {13 Mail::fake();14 15 // Perform order shipping...16 17 // Assert that no mailables were sent...18 Mail::assertNothingSent();19 20 // Assert that a mailable was sent...21 Mail::assertSent(OrderShipped::class);22 23 // Assert a mailable was sent twice...24 Mail::assertSent(OrderShipped::class, 2);25 26 // Assert a mailable was sent to an email address...28 29 // Assert a mailable was sent to multiple email addresses...31 32 // Assert a mailable was not sent...33 Mail::assertNotSent(AnotherMailable::class);34 35 // Assert 3 total mailables were sent...36 Mail::assertSentCount(3);37 }38}
如果您正在佇列可郵件以在背景傳遞,則應使用 assertQueued
方法而不是 assertSent
。
1Mail::assertQueued(OrderShipped::class);2Mail::assertNotQueued(OrderShipped::class);3Mail::assertNothingQueued();4Mail::assertQueuedCount(3);
您可以將閉包傳遞給 assertSent
、assertNotSent
、assertQueued
或 assertNotQueued
方法,以斷言已發送的可郵件通過給定的「真值測試」。如果至少有一個可郵件通過給定的真值測試,則斷言將成功。
1Mail::assertSent(function (OrderShipped $mail) use ($order) {2 return $mail->order->id === $order->id;3});
當呼叫 Mail
facade 的斷言方法時,提供的閉包接受的可郵件實例會公開有助於檢查可郵件的方法。
1Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user) {2 return $mail->hasTo($user->email) &&3 $mail->hasCc('...') &&4 $mail->hasBcc('...') &&5 $mail->hasReplyTo('...') &&6 $mail->hasFrom('...') &&7 $mail->hasSubject('...');8});
可郵件實例還包含幾個有助於檢查可郵件附件的方法。
1use Illuminate\Mail\Mailables\Attachment; 2 3Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) { 4 return $mail->hasAttachment( 5 Attachment::fromPath('/path/to/file') 6 ->as('name.pdf') 7 ->withMime('application/pdf') 8 ); 9});10 11Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {12 return $mail->hasAttachment(13 Attachment::fromStorageDisk('s3', '/path/to/file')14 );15});16 17Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($pdfData) {18 return $mail->hasAttachment(19 Attachment::fromData(fn () => $pdfData, 'name.pdf')20 );21});
您可能已經注意到,有兩種方法可以斷言郵件未發送:assertNotSent
和 assertNotQueued
。有時您可能希望斷言沒有郵件被發送或加入佇列。若要完成此操作,您可以使用 assertNothingOutgoing
和 assertNotOutgoing
方法。
1Mail::assertNothingOutgoing();2 3Mail::assertNotOutgoing(function (OrderShipped $mail) use ($order) {4 return $mail->order->id === $order->id;5});
郵件和本地開發
在開發發送電子郵件的應用程式時,您可能不希望實際發送電子郵件到真實的電子郵件地址。Laravel 提供了幾種方法來在本地開發期間「停用」實際發送電子郵件。
記錄驅動程式
log
郵件驅動程式不會發送您的電子郵件,而是將所有電子郵件訊息寫入您的記錄檔以供檢查。通常,此驅動程式僅在本地開發期間使用。有關為每個環境設定應用程式的更多資訊,請查看設定文件。
HELO / Mailtrap / Mailpit
或者,您可以使用像 HELO 或 Mailtrap 這樣的服務和 smtp
驅動程式,將您的電子郵件訊息發送到「虛擬」信箱,您可以在真正的電子郵件用戶端中檢視它們。這種方法的好處是允許您在 Mailtrap 的訊息檢視器中實際檢查最終的電子郵件。
如果您正在使用 Laravel Sail,您可以使用 Mailpit 預覽您的訊息。當 Sail 執行時,您可以透過以下網址存取 Mailpit 介面:https://127.0.0.1:8025
。
使用全域 to
地址
最後,您可以透過呼叫 Mail
facade 提供的 alwaysTo
方法來指定全域「to」地址。通常,應從應用程式的服務提供者的 boot
方法中呼叫此方法。
1use Illuminate\Support\Facades\Mail; 2 3/** 4 * Bootstrap any application services. 5 */ 6public function boot(): void 7{ 8 if ($this->app->environment('local')) {10 }11}
事件
Laravel 在發送郵件訊息時會分派兩個事件。MessageSending
事件在訊息發送之前分派,而 MessageSent
事件在訊息發送之後分派。請記住,這些事件是在郵件被發送時分派,而不是在郵件加入佇列時分派。您可以在應用程式中為這些事件建立事件監聽器。
1use Illuminate\Mail\Events\MessageSending; 2// use Illuminate\Mail\Events\MessageSent; 3 4class LogMessage 5{ 6 /** 7 * Handle the given event. 8 */ 9 public function handle(MessageSending $event): void10 {11 // ...12 }13}
自訂傳輸器
Laravel 包含各種郵件傳輸方式;但是,您可能希望編寫自己的傳輸方式,以透過 Laravel 開箱即用不支援的其他服務傳遞電子郵件。若要開始,請定義一個擴充 Symfony\Component\Mailer\Transport\AbstractTransport
類別的類別。然後,在您的傳輸方式上實作 doSend
和 __toString()
方法。
1use MailchimpTransactional\ApiClient; 2use Symfony\Component\Mailer\SentMessage; 3use Symfony\Component\Mailer\Transport\AbstractTransport; 4use Symfony\Component\Mime\Address; 5use Symfony\Component\Mime\MessageConverter; 6 7class MailchimpTransport extends AbstractTransport 8{ 9 /**10 * Create a new Mailchimp transport instance.11 */12 public function __construct(13 protected ApiClient $client,14 ) {15 parent::__construct();16 }17 18 /**19 * {@inheritDoc}20 */21 protected function doSend(SentMessage $message): void22 {23 $email = MessageConverter::toEmail($message->getOriginalMessage());24 25 $this->client->messages->send(['message' => [26 'from_email' => $email->getFrom(),27 'to' => collect($email->getTo())->map(function (Address $email) {28 return ['email' => $email->getAddress(), 'type' => 'to'];29 })->all(),30 'subject' => $email->getSubject(),31 'text' => $email->getTextBody(),32 ]]);33 }34 35 /**36 * Get the string representation of the transport.37 */38 public function __toString(): string39 {40 return 'mailchimp';41 }42}
一旦您定義了自訂傳輸方式,您就可以透過 Mail
facade 提供的 extend
方法註冊它。通常,這應在應用程式的 AppServiceProvider
服務提供者的 boot
方法中完成。$config
引數將傳遞給提供給 extend
方法的閉包。此引數將包含在應用程式的 config/mail.php
設定檔中為郵件程式定義的設定陣列。
1use App\Mail\MailchimpTransport; 2use Illuminate\Support\Facades\Mail; 3 4/** 5 * Bootstrap any application services. 6 */ 7public function boot(): void 8{ 9 Mail::extend('mailchimp', function (array $config = []) {10 return new MailchimpTransport(/* ... */);11 });12}
一旦您的自訂傳輸方式已定義和註冊,您就可以在應用程式的 config/mail.php
設定檔中建立一個郵件程式定義,以使用新的傳輸方式。
1'mailchimp' => [2 'transport' => 'mailchimp',3 // ...4],
其他 Symfony 傳輸器
Laravel 包含對一些現有 Symfony 維護的郵件傳輸方式(如 Mailgun 和 Postmark)的支援。但是,您可能希望擴充 Laravel 以支援其他 Symfony 維護的傳輸方式。您可以透過 Composer 要求必要的 Symfony 郵件程式,並向 Laravel 註冊傳輸方式來做到這一點。例如,您可以安裝並註冊「Brevo」(以前稱為「Sendinblue」)Symfony 郵件程式。
1composer require symfony/brevo-mailer symfony/http-client
一旦 Brevo 郵件程式套件安裝完成,您可以將 Brevo API 憑證的項目新增到應用程式的 services
設定檔中。
1'brevo' => [2 'key' => 'your-api-key',3],
接下來,您可以使用 Mail
facade 的 extend
方法向 Laravel 註冊傳輸方式。通常,這應在服務提供者的 boot
方法中完成。
1use Illuminate\Support\Facades\Mail; 2use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory; 3use Symfony\Component\Mailer\Transport\Dsn; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 Mail::extend('brevo', function () {11 return (new BrevoTransportFactory)->create(12 new Dsn(13 'brevo+api',14 'default',15 config('services.brevo.key')16 )17 );18 });19}
一旦您的傳輸方式已註冊,您就可以在應用程式的 config/mail.php 設定檔中建立一個郵件程式定義,以使用新的傳輸方式。
1'brevo' => [2 'transport' => 'brevo',3 // ...4],