Mail

Giới thiệu

Laravel cung cấp API rất gọn và đơn giản thông qua thư viện SwiftMailer với SMTP, Mailgun, SparkPost, Amazon SES, hàm mail của PHP, và sendmail, cho phép bạn nhanh chóng bắt đầu gửi mail qua dịch vụ mail local hay cloud tuỳ theo lựa chọn của bạn.

Điều kiện bắt buộc

Các driver dựa trên API như Mailgun hay Mandrill thường đơn giản và nhanh hơn SMTP server. Tất cả các API driver yêu cầu sử dụng thư viện Guzzle HTTP được cài đặt trong ứng dụng của bạn. Bạn có thể cài đặt vào project bằng cách thêm dòng dưới đây vào trong file:

composer require guzzlehttp/guzzle

Mailgun Driver

Để sử dụng Mailgun driver, đầu tiên cần cài Guzzle, sau đó cấu hình driver trong file config/mail.php vào mailgun. Tiếp theo, xác định rằng file cấu hình đã có config/services.php:

'mailgun' => [
    'domain' => 'your-mailgun-domain',
    'secret' => 'your-mailgun-key',
],

SparkPost Driver

Để sử dụng SparkPost driver, đầu tiên cần phải cài Guzzle, sau đó tùy chỉnh driver trong file cấu hình config/mail.php vào sparkpost. Tiếp theo, bạn phải xác định cấu hình config/services.php chứa tùy chọn sau:

'sparkpost' => [
    'secret' => 'your-sparkpost-key',
],

SES Driver

Để sử dụng Amazon SES driver bạn cần phải cài Amazon AWS SDK cho PHP. Bạn phải cài đặt thư viện này bằng cách thêm nó vào phần require của file composer.json và chạy lệnh composer update:

"aws/aws-sdk-php": "~3.0"

Tiếp theo, đặt tùy chỉnh drivertrong file config/mail.php vào ses và xác định file cấu hình config/services.php chứa đoạn code bên dưới:

'ses' => [
    'key' => 'your-ses-key',
    'secret' => 'your-ses-secret',
    'region' => 'ses-region',  // e.g. us-east-1
],

Tạo Mailables

Trong Laravel,mỗi khi email được gửi đi bởi ứng dụng được đại diện như một class "mailable". Các class đó được lưu trong thư mục app/Mail. Đừng lo lắng nếu bạn không nhìn thấy đường dẫn đó trong ứng dụng của bạn, vì nó sẽ được tạo ra khi bạn tạo class mailable lần đầu tiên bằng cách dùng lệnh make:mail

php artisan make:mail OrderShipped

Viết Mailables

Tất cả của một lớp mailable đều được cấu hình trong phương thức build. Bên trong hàm này, bạn có thể gọi nhiều phương thức như from, subject, view, và attach để cấu hình mail nhận.

Cấu hình người gửi

Sử dụng hàm from

Đầu tiên, hãy tìm hiểu cấu hình email của người gửi. Hoặc, theo một nghĩa khác, người gửi mail là "from". Có hai cách để cấu hình người gửi. Đầu tiên, bạn có thể sử dụng hàm from trong hàm build của class mailable:

/**
 * Build the message.
 *
 * @return  $this
 */
public function build()
{
    return $this->from('example@example.com')
                ->view('emails.orders.shipped');
}

Sử dụng hàm toàn cục from

Tuy nhiên, nếu ứng dụng của bạn sử dụng địa chỉ "from" cho tất cả các mail, nó sẽ trở lên dài dòng để gọi hàm from trong mỗi class mailable bạn tạo ra. Thay vì, bạn có thể chỉ định địa chỉ "from" trong file cấu hình config/mail.php. Địa chỉ này sẽ được sử dụng nếu không có địa chỉ "from" được chỉ định của class mailable:

'from' => ['address' => 'example@example.com', 'name' => 'App Name'],

Cấu hình View

Bên trong hàm build mailable, bạn có thể sử dụng hàm view để chỉ định template được sử dụng khi render nội dung email. Vì mỗi email sử dụng Blade template để render nội dung, bạn có thể có toàn quyền và thoải mái xây dựng Blade templating HTML:

/**
 * Build the message.
 *
 * @return  $this
 */
public function build()
{
    return $this->view('emails.orders.shipped');
}

Bạn nên tạo thư mục resources/views/emails để lưu tất cả các email templates; tuy nhiên, bạn hoàn toàn có thể thay đổi vị trí theo ý bạn bên trong thư mục resources/views.

Plain Text Emails

Nếu bạn muốn định nghĩa một phiên bản plain-text cho email, bạn có thể sử dụng hàm text. Giống như hàm view, hàm textnhận một tên template sẽ được sử dụng để render nội dung của email. Nếu bạn định thoải mái nghĩa một HTML và một phiên bản plain-text cho tin nhắn của bạn:

/**
 * Build the message.
 *
 * @return  $this
 */
public function build()
{
    return $this->view('emails.orders.shipped')
                ->text('emails.orders.shipped_plain');
}

Dữ liệu view

Qua thuộc tính public

Thông thường, bạn sẽ cần truyền một số dữ liệu vào trong view khi rendering ra HTML. Có hai cách bạn có thể hiển thị dữ liệu trong view. Thứ nhất, bất cứ thuộc tính public được định nghĩa trong class mailable sẽ được tự động tồn tại trong view. Vì vậy, ví dụ, bạn có thể truyền dữ liệu có thuộc tính public vào trong hàm khởi tạo của class mailable và đặt dữ liệu bạn muốn truyền vào trong đó:

<?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;

    /**
     * The order instance.
     *
     * @var  Order
     */
    public $order;

    /**
     * Create a new message instance.
     *
     * @return  void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * Build the message.
     *
     * @return  $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped');
    }
}

Khi dữ liệu đã được đặt vào một thuộc tính public public, nó sẽ tự động tồn tại trong view, bạn có thể truy cập nó giống như bạn truy cập bất cứ dữ liệu khác trong Blade templates:

<div>
    Price: {{ $order->price }}
</div>

Qua phương thức with

Nếu bạn muốn tùy biến định dạng dữ liệu trước khi gửi nó vào template, bạn có thể tùy biến dữ liệu của bạn vào view qua hàm with. Thông thường, bạn vẫn truyền dữ liệu qua hàm khởi tạo của class mailable; tuy nhiên, bạn nên đặt dữ liệu thành protected hoặc private nó sẽ không có ở trong view template. Sau đó, khi gọi hàm with, truyền một mảng dữ liệu bạn muốn vào trong template:

<?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;

    /**
     * The order instance.
     *
     * @var  Order
     */
    protected $order;

    /**
     * Create a new message instance.
     *
     * @return  void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

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

Khi dữ liệu đã được truyền vào hàm with, nó sẽ tự động tồn tại ở trong view, bạn có thể truy cập bình thường như khi sử dụng dữ liệu với Blade templates:

<div>
    Price: {{ $orderPrice }}
</div>

Đính kèm

Để đính kèm vào email, sử dụng hàm attach bên trong hàm build của class mailable. Hàm attach chấp nhận đường dẫn đầy đủ của file là tham số thứ nhất:

    /**
     * Build the message.
     *
     * @return  $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped')
                    ->attach('/path/to/file');
    }

Khi đính kèm các file vào một message, bạn có thể chỉ định tên hiển thị và / hoặc MIME type bằng cách truyền vào array như là tham số thứ hai của phương thức attach:

    /**
     * Build the message.
     *
     * @return  $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped')
                    ->attach('/path/to/file', [
                        'as' => 'name.pdf',
                        'mime' => 'application/pdf',
                    ]);
    }

Raw Data Attachments

Hàm attachData bạn có thể sử dụng để đính kèm một raw string của bytes như một đính kèm. Ví dụ, bạn có thể sử dụng phương thức này nếu bạn muốn sinh một PDF trong memory và muốn đính kèm nó vào email mà không cần viết nó vào ổ cứng. Hàm attachData chấp nhận dữ liệu dạng raw data bytes là tham số thứ nhất, tên của file là tham số thứ hai, và một mảng tùy biến là tham số thứ ba:

    /**
     * Build the message.
     *
     * @return  $this
     */
    public function build()
    {
        return $this->view('emails.orders.shipped')
                    ->attachData($this->pdf, 'name.pdf', [
                        'mime' => 'application/pdf',
                    ]);
    }

Inline Attachments

Nhúng ảnh inline vào emails thông thường là không đơn giản; tuy nhiên, Laravel cung cấp khá thuận tiện để bạn đính kèm ảnh vào emails và nhận CID thích hợp. Để nhúng một ảnh inline, sử dụng hàm embed trong biến $message trong email template. Laravel tự động tạo biến $message tồn tại cho tất cả email templates, vì vậy bạn không cần phải truyền nó một cách thủ công:

<body>
    Here is an image:

    <img src="{{ $message->embed($pathToFile) }}">
</body>

Nhúng Raw Data Attachments

Nếu bạn có một raw data string bạn muốn nhúng vào email template, bạn có thể sử dụng hàm embedData trong biến $message:

<body>
    Here is an image from raw data:

    <img src="{{ $message->embedData($data, $name) }}">
</body>

Sending Mail

Để gửi một tin nhắn, sử dụng hàm to trong Mail facade. Hàm to chấp nhận một địa chỉ email, một user instance, hoặc một collection của users. Nếu bạn muốn truyền một object hoặc một collection của objects, mailer sẽ tự động sử dụng thuộc tính emailname khi thiết lập email nhận, và đảm bảo rằng thuộc tính tồn tại trong objects. Khi bạn đã chỉ định mail nhận, bạn có thể truyền một instance vào hàm send class mailable:

<?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
{
    /**
     * Ship the given order.
     *
     * @param    Request  $request
     * @param    int  $orderId
     * @return  Response
     */
    public function ship(Request $request, $orderId)
    {
        $order = Order::findOrFail($orderId);

        // Ship order...

        Mail::to($request->user())->send(new OrderShipped($order));
    }
}

Tất nhiên, bạn có thể không "giới" hạn gửi mail cho người nhận khi gửi mộttin nhắn. Bạn có thể tự do thiết lập "to", "cc", và "bcc" người nhận bên trong, gắn vào phương thức gọi:

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->send(new OrderShipped($order));

Queueing Mail

Queueing A Mail thông điệp

Khi gửi một tin nhắn bằng email có thể kéo dài thời gian trả về response của ứng dụng, nhiều lập trình viên chọn queue email để làm việc đó. Laravel tạo nó rất đơn giản để built-in unified queue API. Để queue một mail tin nhắn, sử dụng hàmqueue trong Mail facade sau khi chỉ định mail người nhận:

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue(new OrderShipped($order));

Hàm này sẽ tự động pushing một job vào trong queue để gửi thông điệp. Tất nhiên, bạn sẽ cần phải cấu hình cấu hình queues trước khi sử dụng tính năng này.

Hoãn thông điệp Queueing

Nếu bạn muốn hoãn phục vụ một queued email, bạn có thể dùng hàm later. Như đối số đầu tiên, hàm later nhận một thể hiện DateTime khi thông điệp được gửi:

$when = Carbon\Carbon::now()->addMinutes(10);

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->later($when, new OrderShipped($order));

Pushing vào Queues chỉ định

Vì tất cả các class mailable được tạo ra sử dụng lệnh make:mail sư dụng Illuminate\Bus\Queueable trait, bạn có thể gọi hàm onQueueonConnection trong bất kỳ class mailable, cho phép bạn chỉ định kết nối và tên queue cho thông điệp:

$message = (new OrderShipped($order))
                ->onConnection('sqs')
                ->onQueue('emails');

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->queue($message);

Queueing mặc định

Nếu bạn có class mailable mà bạn muốn cho vào queued, bạn có thể làm ShouldQueue contract trong class. Bây giờ, nếu bạn gọi hàm send khi đang gửi mail, mailable sẽ vẫn được cho vào queue vì nó implements contract:

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    //
}

Mail & Local Development

Khi phát triển một ứng dụng có gửi email, có thể bạn không cần phải gửi mail trực tiếp. Laravel cung cấp một vài cách để "disable" gửi mail trong môi trường phát triển.

Log Driver

Thay vì gửi mail của bạn, hàm log mail driver sẽ viết tất cả các thông điệp mail vào file log để kiểm tra. Tìm hiểu thêm thông tin cấu hình ứng dụng trên từng môi trườngxem tại configuration documentation.

Universal To

Một cách khác mà Laravel cung cấp là đặt một đặt một mail để gửi cho tất cả framework. Cách này, tất cả các mail được tạo ra bởi ứng dụng sẽ được gửi đến mail một chỉ định, thay vì chỉ định mail khi gửi mail. Để thực hiện cần phải cấu hình trong to option in your config/mail.php

'to' => [
    'address' => 'example@example.com',
    'name' => 'Example'
],

Mailtrap

Cuối cùng, bạn có thể sử dụng dịch vụ mail như Mailtrapsmtp driver để gửi thông điệp mail của bạn đến một "dummy" mailbox nơi mà bạn có thể xem chúng như người nhận. Cách tiếp cận này khá hữu ích cho bạn kiểm tra mail.

Events

Laravel bắn ra một event trước khi gửi mail. Nhớ rằng, event này được bắn khi mail đã gửi, nó không như queued. Bạn có thể đăng ký một event listener cho event này trong EventServiceProvider:

/**
 * The event listener mappings for the application.
 *
 * @var  array
 */
protected $listen = [
    'Illuminate\Mail\Events\MessageSending' => [
        'App\Listeners\LogSentMessage',
    ],
];
Nguồn: https://laravel.com/docs/5.3/mail