Gửi mail trong Laravel 5.3

Giới thiệu

Gửi mail là một hoạt động rất hữu ích và cần thiết của hầu hết các ứng dụng. Trước đấy để gửi mail việc lựa chọn thư viện và config khá phức tạp. Nhưng hiện nay, Laravel đã cung cấp một API rõ ràng và đơn giản thông qua thư viện phổ biến SwiftMailer với các driver như SMTP, Mailgun, SparkPost, Amazon SES, giúp gửi mail rất đơn giản và dẽ dàng.

Chuẩn bị

Hầu hết các API drivers yêu cầu Guzzle HTTP library, nó có thể được cài đặt thông qua Composer:

composer require guzzlehttp/guzzle

Khởi tạo Mailable

Trong Laravel mỗi loại email được gửi bởi ứng dụng được xem như là một “mailable” class. Và được đặt ở thư mục app/Mail. Thư mục này sẽ đươc tạo ở lần đầu tiên tạo mailable class qua command make:mail:

php artisan make:mail OrderShipped

Viết Mailables

Tất cả cấu hình của một Mailable class được thực hiện ở phương thức build của class. Trong phương thức này chúng ta có thể gọi các phương thức khác như from, subject, view, attach để config, chỉnh sửa nội dung cũng như giao diện.

Config người gửi

Sử dụng phương thức from. Có 2 cách để config người gửi:

Sử dụng phương thức from trong hàm build

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

Sử dụng biến địa chỉ Global from

Mặt khác, chúng ta có thể sử dụng biến global from trong file cấu hình config/mail.php. Địa chỉ này sẽ được sử dụng nếu không chỉ định from address trong mailable class.

'from' => ['address' => '[email protected]', 'name' => 'App Name'],

Config giao diện

Trong phương thức build chúng ta có thể sử dụng phương thức view để chỉ định template được rendering (sử dụng Blade template) khi xây dựng email HTML.

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

Chúng ta có thể tạo một thư mục resources/views/emails đẻ lưu trữ các email template.

Plain Text Emails

Nếu muốn định nghĩa một phiên bản plain-text để gửi mail, chúng ta có thể sử dụng phương thức text. Giống như hàm view, hàm text chấp nhận một template chưa nội dung email.

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

Gán dữ liệu qua view

Thông qua thuộc tính public

Thông thường chúng ta cần gán dữ liệu qua view để hiện thị. Có 2 cách để pass dữ liệu qua view. Đầu tiên, bất cứ thược tính public nào được định nghĩa ở mailable class đều tự động pass qua view. Nghĩa là mình sẽ hiển thị được luôn mà không cần phải gán. Ví dụ:

<?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');
    }
}

Biến $order là biến public nên nó tự động được truy cập ở view.

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

Thông qua phương thức with

Đối với các biến có thuộc tính là protectedprivate thì có thể pass dữ liệu qua view bằng phương thức 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;

    /**
     * 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,
                    ]);
    }
}

Mỗi lần dữ liệu được gán qua phương thức with, chúng tự động được truy cập ở view:

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

Đính kèm file

Để đính kèm file, sử dụng phương thức attach, nhận đường dẫn của file làm tham số đầu tiên. Tham số thứ 2 là mảng chưa tên file, loại file:


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

Còn có phương thức attachData được sử dụng để đính kèm 1 chuỗi ký tự như một file đính kèm. Ví dụ, nếu chúng ta sinh ra một file PDF trong một nhớ và muốn đính kèm email mà ko muốn ghi ra đĩa cứng. Phương thức attachData nhận nội dung string như là tham số đầu tiên, tên của file là tham số thứ 2, và mảng optional là tham số thứ 3.

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

Nội đính kèm (Inline attachments)

Chúng ta có thể đính kèm file sử dụng phương thức embed của biến $message trong email template. $message là biến global và có thể truy cập ở mọi email template mà không cần phải gán qua view.

<body>
    Here is an image:

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

Đính kèm chuỗi nội dung (Embedding Raw Data Attachments) Chuỗi nội dung có thể được nhúng trong một email template thông qua phương thức embedData của biến $message:

<body>
    Here is an image from raw data:

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

Config mail server

Config biến MAIL .env


    MAIL_DRIVER=smtp
    MAIL_HOST=smtp.abc.com
    MAIL_PORT=587
    MAIL_USERNAME=[email protected].com
    MAIL_PASSWORD=password
    MAIL_ENCRYPTION=tls

Ngoài ra config thêm địa chỉ người gửi và tên người from trong file config/mail.php. Nếu không chỉ định người gửi bằng phương thức from trong Mailable class thì nó sẽ lấy giá trị này làm giá trị người người mặc định.


    'from' => [
        'address' => '[email protected]',
        'name' => 'Mr David',
    ],

Gửi mail

Để gửi mail, sử dụng phương thức to của Mail facade. Phương thức to chấp nhận một địa chỉa email, một user instance, hoặc một tập hợp các users. Nếu truyền vào tham số là object hoặc tập hợp (collection) các object, mailer sẽ tự động sử dụng thuộc tính emailname để setting địa chỉ người nhận. Sau đó dùng phương thức send để gửi mail.

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

Laravel còn cung cấp thêm các hàm cc, bcc để thêm người nhận.

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

Queueing Mail

Queue một tin nhắn email

Thường thi gửi mail mất khá nhiều thời gian nên chúng ta thường ném vào queue và chạy background để gửi mail đi. Để queue email message sử dụng phương thức queue của Mail facade.

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

Để xem thêm về Queue chúng ta tham khảo tại trang chủ của Laravel Queues.

Delayed Message Queueing

Nếu chúng ta cần delay việc gửi mail của các email message đã được queue sử dụng method later. Phương thức later nhận một Datetime instance làm đối số.

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

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

Đẩy email message vào queue chỉ định

Tất cả các mailable classes sinh ra bời command make:mail sử dụng Illuminate\Bus\Queue trait, có thể sử dụng 2 phương thức onQueueonConnnection để chỉ định tên queue và tên connection.

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

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

Queue mặc định

Nếu bạn có mailable classes muốn luôn luôn được queue thì bạn phải implement contract ShouldQueue.

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue
{
    //
}

Run Queues

Sau khi ném email message vào Queue, chúng ta phải chạy job queue emails để gửi email.


php artisan queue:work redis queue=emails

Kết luận

Việc gửi mail trong Lavavel rất đơn giản và tiện lợi. Tùy từng ứng dụng mà chúng ta có thể sử dụng các config thích hợp.

Tham khảo