Laravel send email using queue

  • May 8, 2021
  • 2236

Gửi email là tính năng mà hầu hết các ứng dụng web đều phải sử dụng, gửi email có thể  bất đồng bộ vì vậy để tối ưu hiệu suất của ứng dụng thì thường sử dụng queue. Hôm nay chúng ta cùng tìm hiểu xem làm thế nào để gửi được email sử dụng queue với laravel nhé. Trước tiên chúng ta cần đọc thêm bài viết về laravel queue để hiểu thêm các kiến thức và cách sử dụng queue với laravel.

Laravel cung cấp sẵn thư viện để gửi email thông qua SMTP, Mailgun, Postmark, Amazon SES ... email có thể được gửi từ local hoặc từ server.

1. Config email in laravel

Các config email được để trong file config/mail.php để test email chúng ta thường sử dụng Mailtrap
Cấu hình email sử dụng các biến môi trường trong file .env


// Config email with mailtrap
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null

// Config email with AWS
MAIL_MAILER=smtp
MAIL_HOST=
MAIL_PORT=587
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=null

2. Create Mailable

Tạo emailable đơn giản chỉ cần sử dụng command


php artisan make:mail OrderShipped

các class Mailable sẽ được tạo trong thư mục app/Mail, nội dung của 1 class mailable


<?php

namespace App\Mail;

use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    protected $order;
    protected $subject;

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

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->from(config('mail.from.address'))
            ->subject($this->subject)
            ->view('emails.orders.shipped')
->with(['price' => $this->order->price]); } }

Tạo email template emails/orders/shipped.blade.php


Price: {{ $price }}

3. Create job send email

Sử dụng command để tạo job


php artisan make:job OrderShippedJob

Tạo job gửi email tới 1 địa chỉ email


<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Mail;

class OrderShippedJob implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    protected $to;
    protected $mail;

    /**
     * Create a new job instance.
     * OrderShippedJob constructor.
     *
     * @param string $to
     * @param Mailable $mail
     */
    public function __construct(string $to, Mailable $mail)
    {
        $this->to = $to;
        $this->mail = $mail;
    }

    /**
     * Execute the job.
     */
    public function handle()
    {
        Mail::to($this->to)->send($this->mail);
    }
}

Tạo job gửi tới nhiều địa chỉ email


<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Mail;

class SendOrderToAdminJob implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    protected $to;
    protected $mail;

    /**
     * Create a new job instance.
     * SendOrderToAdminJob constructor.
     *
     * @param array $to
     * @param Mailable $mail
     */
    public function __construct(array $to, Mailable $mail)
    {
        $this->to = $to;
        $this->mail = $mail;
    }

    /**
     * Execute the job.
     */
    public function handle()
    {
        Mail::to($this->to)->send($this->mail);
    }
}

4. Tạo controller thực hiện gửi email


<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Mail\OrderShipped;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Jobs\OrderShippedJob;

class OrderShipmentController extends Controller
{
    /**
     * Ship the given order.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function SendEmailToShip(Request $request)
    {
        $order = Order::findOrFail($request->order_id);
        $email = 'test@gmail.com';
        // Ship the order...
        $subject = 'Test order mail';
        $mailable = new OrderShipped($order, $subject);
        
        dispatch(new OrderShippedJob($email, $mailable));
    }

   /**
     * Admin the given order.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function SendEmailToAdmin(Request $request)
    {
        $order = Order::findOrFail($request->order_id);
        $emails = ['test@gmail.com', 'test2@gmail.com'];
        // Ship the order...
        $subject = 'Test order mail';
        $mailable = new OrderShipped($order, $subject);
        
        dispatch(new OrderShippedJob($emails, $mailable));
    }
}

5. Send email without mailable

Có những lúc không cần sử dụng mailable thì sao, đừng lo laravel đã hỗ trợ đến tận răng rồi nhé. Thường được sử dụng khi bạn muốn quản lí template email từ admin


// Send a raw message (in plain text) 
Mail::raw('Hello, welcome to Laravel!', function ($message) {
  $message
    ->to(...)
    ->subject(...);
});

// Send an html message
Mail::html($html, function ($message) {
  $message
    ->to(...)
    ->subject(...);
});

// Send plain text emails with variable
Mail::plain('Hello {{ $user }}, welcome to Laravel!', ['user' => 'John Doe'], function ($message) {
  $message
    ->to(...)
    ->subject(...);
});

6. Test config email in AWS

Để test cấu hình email trên server AWS bạn dùng telnet đến server aws mail ses qua cổng 587. Document send email aws và các lỗi có thể gặp với Amazon SES SMTP

telnet [aws_server] 587

Trên đây là toàn bộ các bước để gửi email sử dụng queue với laravel, hi vọng bài viết sẽ giúp ích cho mọi người khi làm chức năng liên quan đến gửi email.