郵件發送
mail 函數,以及 sendmail
提供了驅動,從而允許你快速透過本地或雲端服務發送郵件。 郵件驅動預備知識基於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' => [ '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 的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 時需要包含附加選項 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', ], ], ], ],##。可郵寄類在Laravel 中,應用程式發送的每一封郵件都可以表示為「可郵寄」 類,這些類別都存放在
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
方法就顯得很累贅。取而代之地,你可以在設定檔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'],
#設定檢視
你可以在可郵寄類別的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 視圖以供使用。有兩種方式將資料傳遞到視圖,首先,您的 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>
附件
要在郵件中加入附件,在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', ]); }
從磁碟中新增附件
#如果您已在文件儲存上儲存了一個文件,則可以使用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', ]); }
內聯附件
在郵件中嵌入內聯圖片通常都很麻煩;不過,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>
自訂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 格式的Mailables 類別
Markdown 格式mailable 訊息可讓你從預先建置範本和mailable 類別中的郵件通知元件獲益。由於訊息使用 Markdown 書寫,Laravel 能夠渲染出美觀的、響應式的 HTML 模板訊息,也能自動產生文字副本。
產生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'); }##寫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 | | | Col 3 is | Right-Aligned | | @endcomponent
自訂元件
可以將所有 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 文件,並修改theme
選項。
發送郵件
若要傳送郵件,使用Mail
facade 的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));
渲染Mailable
有時可能想要捕捉mailable 的HTML 內容,而不會傳送它。可以呼叫 mailable 的 render
方法實作此目的。此方法傳回mailable 渲染計算後的字串:
$invoice = App\Invoice::find(1); return (new App\Mail\InvoicePaid($invoice))->render();
#在瀏覽器中預覽Mailable
設計mailable模板時,像Blade 模板一樣在瀏覽器中預覽和渲染mailable 是很方便的。在這種情況下,Laravel 允許你在路由閉包或控制其中直接返回任意 mailable。返回的mailable 會在瀏覽器中渲染和顯示,你可以快速預覽設計效果,而不需要將其發送到真實的郵件地址:
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
指令產生的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{ // }
Laravel 允許你使用有別於目前語言的區域設定發送mailable,即使加入到佇列中也保留該區域設定。
為達到此目的,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));#####################郵件& 本機開發### ###在開發發送郵件的應用程式時,你也許不想真的向即時郵件地址發送郵件。 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', ], ];