Laravel - Digging Deeper - Mail (官方文件原子化翻譯筆記)

# Introduction

學習一個框架, Ray 的想法是, 在深入理解底層實作的原理之前, 應該先知道這個框架的 使用方法; 先學習怎麼使用這個前人造的輪子, 再學習怎麼樣一個輪子。
所以本篇文章重點在於細讀官方文件, 並將內容理解後以 Q&A 的方式記錄下來, 加速學習以及查詢。



# Driver / Transport Prerequisites

# Mailgun Driver

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // config/services.php
    'mailgun' => [
    'domain' => env('MAILGUN_DOMAIN'),
    'secret' => env('MAILGUN_SECRET'),
    'endpoint' => env('MAILGUN_ENDPOINT', 'api.eu.mailgun.net'),
    ],
  • Answer:
    設定 mail driver mailgun service, 如果不是使用 United States Mailgun region, 可以自定義在 endpoint

# Postmark Driver

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    composer require wildbit/swiftmailer-postmark
  • Answer:
    使用 postmark mail driver 需要安裝的套件
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // config/services.php
    'postmark' => [
    'token' => env('POSTMARK_TOKEN'),
    ],
  • Answer:
    mail driver psotmark 的設定
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // config/mail.php
    'postmark' => [
    'transport' => 'postmark',
    'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
    ],
  • Answer:
    可自定義 postmark mail driver 的 message_stream

# SES Driver

以下的 Laravel example code 的意思是?
  • Example:
    composer require aws/aws-sdk-php
  • Answer:
    要在 Laravel 使用 AWS 的服務, 如 s3, SES, SQS 時, 需安裝 AWS SDK
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // config/services.php
    'ses' => [
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
    'options' => [
    'ConfigurationSetName' => 'MyConfigurationSet',
    'Tags' => [
    ['Name' => 'foo', 'Value' => 'bar'],
    ],
    ],
    ],
  • Answer:
    除了 AWS 預設的 key, secret, region 之外, 還可設置 additional 的 setting

# Generating Mailables

以下的 Laravel example code 的意思是?
  • Example:
    php artisan make:mail OrderShipped
  • Answer:
    建立一個 mailable class, 會放在 app/Mail

# Writing Mailables

# Configuring The Sender

# Using The from Method

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // in mailable class
    public function build()
    {
    return $this->from('example@example.com')
    ->view('emails.orders.shipped');
    }
  • Answer:
    在 mailable class 的 build 中, 可以使用 from 來指定由的 from

# Using A Global from address

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // config/mail.php
    'from' => ['address' => 'example@example.com', 'name' => 'App Name'],
  • Answer:
    可在 config/mail.php 定義 global 的 from, 即寄件人信箱, 若需要 ad hoc 可在 mailable class 的 build method 中使用 from() 定義
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // config/mail.php
    'reply_to' => ['address' => 'example@example.com', 'name' => 'App Name'],
  • Answer:
    定義 reply_to address
    當收到 mail 時, 預設按下 reply 會寄給 FROM address, 若要指定一個跟 FROM address 不同的 reply address, 可在此定義

# Configuring The View

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->view('emails.orders.shipped');
    }
  • Answer:
    在 mailable class 的 build method 內, 使用 view() 來指定渲染該 mail 的 template

# Plain Text Emails

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->view('emails.orders.shipped')
    ->text('emails.orders.shipped_plain');
    }
  • Answer:
    可以同時定義 HTML 以及 plain text version, 當 user 切換為 plain text version 時, 就會顯示該版本

# View Data

# Via Public Properties

以下的 Laravel example code 的意思是?
  • Example:
    <?php

    namespace App\Mail;

    class OrderShipped extends Mailable
    {
    use Queueable, SerializesModels;

    public $order;

    public function __construct(Order $order)
    {
    $this->order = $order;
    }

    public function build()
    {
    return $this->view('emails.orders.shipped');
    }
    }

    // on template
    <div>
    Price: {{ $order->price }}
    </div>
  • Answer:
    當使用 mailable class 時, 可在 constructor 內定義 property, 此 property 可在 template 中被調用

# Via The with Method:

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class OrderShipped extends Mailable
    {
    use Queueable, SerializesModels;

    protected $order;

    public function __construct(Order $order)
    {
    $this->order = $order;
    }

    public function build()
    {
    return $this->view('emails.orders.shipped')
    ->with([
    'orderName' => $this->order->name,
    'orderPrice' => $this->order->price,
    ]);
    }
    }

    // template file
    <div>
    Price: {{ $orderPrice }}
    </div>
  • Answer:
    如果 mailable 中的 property 使用 protected 或 private 的話, 則必須使用 with() 將 data pass 過去

# Attachments

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->view('emails.orders.shipped')
    ->attach('/path/to/file', [
    'as' => 'name.pdf',
    'mime' => 'application/pdf',
    ]);
    }
  • Answer:
    在 mailable class 的 build method 中, 可以使用 attach() 定義 attachment, arg2 還可以定義檔名以及 mine type

# Attaching Files from Disk

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->view('emails.orders.shipped')
    ->attachFromStorage('/path/to/file', 'name.pdf', [
    'mime' => 'application/pdf'
    ]);
    }
  • Answer:
    在 mailable class 的 build method 中, 使用 attachFromStorage, attach filesystem disk 的 file 到 email, arg2 可指定檔名, arg3 可指定 mine type
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->view('emails.orders.shipped')
    ->attachFromStorageDisk('s3', '/path/to/file');
    }
  • Answer:
    在 mailable class 的 build method 中, 使用 attachFromStorageDisk, attach filesystem disk 的 file 到 email, arg1 可指定要使用哪一個 disk

# Raw Data Attachment

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->view('emails.orders.shipped')
    ->attachData($this->pdf, 'name.pdf', [
    'mime' => 'application/pdf',
    ]);
    }
  • Answer:
    attach raw data, 通常是 attach 當次 request 產生的 pdf, 在 memory 中, 並沒有存到 disk 中, arg2 可指定檔名 arg3 可指定 mine type

# Inline Attachments

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    <body>
    Here is an image:

    <img src="{{ $message->embed($pathToImage) }}">
    </body>
  • Answer:
    email template 中, 可以使用 $message variable 的 embed method 來實現 inline attachment

# Embedding Raw Data Attachments

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    <body>
    Here is an image from raw data:

    <img src="{{ $message->embedData($data, 'example-image.jpg') }}">
    </body>
  • Answer:
    在 mail template 中, 如果 memory 中已有檔案, 可以使用 embedData method 來實現 inline attachment

# Customizing The SwiftMailer Message

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    $this->view('emails.orders.shipped');

    $this->withSwiftMessage(function ($message) {
    $message->getHeaders()->addTextHeader(
    'Custom-Header', 'Header Value'
    );
    });
    }
  • Answer:
    在 mailable class 的 build method 中, 使用 withSwiftMessage(), 可註冊一個 closure, 會跟著 SwiftMailer message instance 被觸發, 可在送出 mail 前做一些客製化

# Markdown Mailables

# Generating Markdown Mailables

以下的 Laravel example command 的意思是?
  • Example:
    <?php
    php artisan make:mail OrderShipped --markdown=emails.orders.shipped
  • Answer:
    建立一個 mailable class, 以及相對應的 markdown template
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    public function build()
    {
    return $this->from('example@example.com')
    ->markdown('emails.orders.shipped', [
    'url' => $this->orderUrl,
    ]);
    }
  • Answer:
    在 mailable class 的 build method 中, 使用 markdown(), arg1 指定 markdown template, arg2 可帶入 array, 該 array data 會在 template 中可被以變數的方式使用

# Writing Markdown Messages

以下的 Laravel Mailable Markdown Template example code 的意思是?
  • Example:
    <?php
    @component('mail::message')
    # Order Shipped

    Your order has been shipped!

    @component('mail::button', ['url' => $url])
    View Order
    @endcomponent

    Thanks,<br>
    {{ config('app.name') }}
    @endcomponent
  • Answer:
    Laravel 的 Mailable Markdown Template 結合了 Blade 的 component 以及 Markdown 語法, 可使用 Laravel 預設的 email UI component

# Button Component

以下的 Laravel Mailable Markdown Template example code 的意思是?
  • Example:
    <?php
    @component('mail::button', ['url' => $url, 'color' => 'success'])
    View Order
    @endcomponent
  • Answer:
    使用 Laravel 內建的 email UI component, 為一個 button, 可指定 url 以及 color, color 又可指定 primary, success, 以及 error

# Panel Component

以下的 Laravel Mailable Markdown Template example code 的意思是?
  • Example:
    <?php
    @component('mail::panel')
    This is the panel content.
    @endcomponent
  • Answer:
    使用 Laravel 內建的 email UI component, panel 的效果會讓該區塊的背景顏色稍為不同, 可以達到引起注意力的效果

# Table Component

以下的 Laravel Mailable Markdown Template example code 的意思是?
  • Example:
    <?php
    @component('mail::table')
    | Laravel | Table | Example |
    | ------------- |:-------------:| --------:|
    | Col 2 is | Centered | $10 |
    | Col 3 is | Right-Aligned | $20 |
    @endcomponent
  • Answer:
    使用 Laravel 內建的 email UI component, 就是 Markdown table 的效果

# Customizing The Components

以下的 Laravel example commadn 的意思是?
  • Example:
    <?php
    php artisan vendor:publish --tag=laravel-mail
  • Answer:
    可以匯出 Laravel 內建的 mail template, 匯出後可依照自己的需求去做進一步客製化, 會匯出到 resources/views/vendor/mail 資料夾

# Customizing The CSS

Laravel 中, 如果我要客製化 Markdown template 的 CSS, 該怎麼做?
  1. 在 export components 後, 修改 resources/views/vendor/mail/html/themes 資料夾中的 default.css
  2. resources/views/vendor/mail/html/themes 資料夾中建立一個新的 CSS file, 並在 config/mail.php 中修改 theme 要吃的檔案
  3. 若要針對單一 mailable class 修改, 可在 mailable class 中的 $theme property 中, 指定要吃的 theme css file

# Sending Mail

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class OrderShipmentController extends Controller
    {
    public function store(Request $request)
    {
    $order = Order::findOrFail($request->order_id);

    // Ship the order...

    Mail::to($request->user())->send(new OrderShipped($order));
    }
    }
  • Answer:
    使用 Mail facade 的 to(), 指定收件人, 會自動到該 User model 尋找 name column 以及 email column, 然後再指定 mailable class
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->send(new OrderShipped($order));
  • Answer:
    也可使用 cc (Carbon Copy) 以及 bcc (Blind Carbon Copy) method 來寄信

# Looping Over Recipients

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    foreach (['taylor@example.com', 'dries@example.com'] as $recipient) {
    Mail::to($recipient)->send(new OrderShipped($order));
    }
  • Answer:
    有時會需要使用 loop 來將同一個 mailable class 寄給很多收件人, 這時務必在每一個 iteration 中都要使用 new Mailable Instance, 否則 to() 會將 email append 到 mailable instance, 這樣就會變成每一個 iteration 都會寄給之前的所有收件人

# Sending Mail Via A Specific Mailer

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Mail::mailer('postmark')
    ->to($request->user())
    ->send(new OrderShipped($order));
  • Answer:
    Laravel 預設會使用 config/mail.php 中的 default mailer 來寄信, 也可使用 mailer() 來特別指定

# Queueing Mail

# Queueing A Mail Message

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue(new OrderShipped($order));
  • Answer:
    使用 queue 來發送 mail

# Delayed Message Queueing

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->later(now()->addMinutes(10), new OrderShipped($order));
  • Answer:
    使用 later(), 可以發送 delayed queue message

# Pushing To Specific Queues

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $message = (new OrderShipped($order))
    ->onConnection('sqs')
    ->onQueue('emails');

    Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue($message);
  • Answer:
    使用 queue 發送 mail, 並指定其 connection 以及 queue

# Queueing By Default

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use Illuminate\Contracts\Queue\ShouldQueue;

    class OrderShipped extends Mailable implements ShouldQueue
    {
    //
    }
  • Answer:
    如果已經確定這個 mailable 會固定使用 queue 來發送, 可以 implement ShouldQueue interface

# Queued Mailables & Database Transaction

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use Illuminate\Contracts\Queue\ShouldQueue;

    class OrderShipped extends Mailable implements ShouldQueue
    {
    public $afterCommit = true;
    }
  • Answer:
    有時我們會在 transaction 中發送 queued mailable, 但在 transaction 完成之前 mailable 就已經 dispatch 了, 這會造成預期外的錯誤, 如要避免此情況, 可將 mailable class 的 $afterCommit property 設為 true, 這樣 queued mail 就會等到當下所有的 open transaction 都完成了才會寄出

# Rendering Mailables

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use App\Mail\InvoicePaid;
    use App\Models\Invoice;

    $invoice = Invoice::find(1);

    return (new InvoicePaid($invoice))->render();
  • Answer:
    render method 會以 string 的方式 return HTML content

# Previewing Mailables In The Browser

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Route::get('/mailable', function () {
    $invoice = App\Models\Invoice::find(1);

    return new App\Mail\InvoicePaid($invoice);
    });

  • Answer:
    在設計 mailable class 時, 會希望可以即時地看到畫面, 這時可以直接 return mailable instance
    需注意這並不會 return inline attachment, 如需測試 inline attachment, 可使用 MailHog 或 HELO

# Localizing Mailables

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Mail::to($request->user())->locale('es')->send(
    new OrderShipped($order)
    );
  • Answer:
    使用 locale() 來指定 locale

# User Preferred Locales

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use Illuminate\Contracts\Translation\HasLocalePreference;

    class User extends Model implements HasLocalePreference
    {
    public function preferredLocale()
    {
    return $this->locale;
    }
    }
    // in controller
    Mail::to($request->user())->send(new OrderShipped($order));
  • Answer:
    當 notifiable model implement HasLocalePreference interface 之後, 可在 preferredLocale() 中定義要使用的 locale, 當使用 to() 發送 mailable 給指定 user 時, 會自動抓取資料庫中的 locale

# Testing Mailables

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use App\Mail\InvoicePaid;
    use App\Models\User;

    public function test_mailable_content()
    {
    $user = User::factory()->create();

    $mailable = new InvoicePaid($user);

    $mailable->assertSeeInHtml($user->email);
    $mailable->assertSeeInHtml('Invoice Paid');

    $mailable->assertSeeInText($user->email);
    $mailable->assertSeeInText('Invoice Paid');
    }
  • Answer:
    可使用 mailable testing method 來驗證 mailable 是否包含指定的 string, assertSeeInHtml 跟 assertSeeInText 差別在於 HTML version mail 跟 plain text version mail

# Mail & Local Development

Laravel 中, 如果要測試 mail 是否有被發送, 可使用哪兩種方式?

Log driver 或一些其他的服務, 像是 HELO, Mailtrap, MailHog


# Events

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    protected $listen = [
    'Illuminate\Mail\Events\MessageSending' => [
    'App\Listeners\LogSendingMessage',
    ],
    'Illuminate\Mail\Events\MessageSent' => [
    'App\Listeners\LogSentMessage',
    ],
    ];
  • Answer:
    可註冊 listener 監聽兩種 mail event, MessageSending event 在 mail 發送前被觸發, MessageSent 在發送後觸發, 注意如果只是 queue 的話並不會觸發, 待該 job 真正被 worker pick up 被執行時才會觸發
Laravel - Digging Deeper - Task Scheduling (官方文件原子化翻譯) 怎麼在 Laravel 中, 利用 AWS SES 發郵件?

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×