郵件發送


#

Mail

事件

#簡介Laravel 基於SwiftMailer

函式庫提供了一套乾淨、清爽的郵件API。 Laravel 為 SMTP、Mailgun、SparkPost、Amazon SES、PHP 的

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 地區
    ,您可以在### 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 的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 方法中完成,在這個方法中,你可以呼叫多個方法,例如fromsubjectview, 和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 方法手動傳遞資料到視圖。一般情況下,你還是需要透過可郵寄類別的建構器傳遞數據,不過,這次你需要設定資料為 protectedprivate 屬性,這樣,這些資料就不會在視圖中自動生效。然後,當呼叫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。顏色選項支援 primarysuccesserror。你可以隨心所欲地為訊息添加任意數量的按鈕元件:

@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 目錄包含 htmltext 子目錄, 分別包含各自對應的可用元件描述。可以按照自己的意願自訂這些組件。

自訂CSS

組成匯出以後,resources/views/vendor/mail/html/themes 目錄有一個default. css 檔案。可以自此文件中自訂 CSS,這些樣式將自動內聯到 Markdown 郵件訊息的 HTML 表示中。

{tip} 如果想要為Markdown 元件建立完整的新主題,可以在html/themes 目錄新建立一個CSS 文件,並修改mail 配置文件的 theme 選項。

發送郵件

若要傳送郵件,使用Mail facade 的to 方法。 to 方法接受 郵件地址、使用者實例或使用者集合。如果傳遞物件或物件集合,mailer 在設定收件者時將自動使用它們的 emailname 屬性,因此請確保物件的這些屬性可用。一旦制定了收件人,就可以將 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 類別實例上呼叫onQueueonConnection 方法來指定訊息的連線和佇列名稱:

$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{ 
   //
 }

#本地化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));
#####################郵件& 本機開發### ###在開發發送郵件的應用程式時,你也許不想真的向即時郵件地址發送郵件。 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', 
        ],
   ];
本文章首發在 LearnKu.com 網站上。