由於內建的 Authentication 功能,使用內建的信件模板(如下),一般網站通常都會希望使用自己的信件模板,所以必須修改或重建一個新的通知信模板。

前置

要有一個可以發送信件的信箱,Laravel 安裝完時,已經幫你預想好可以使用 Mailtrap.io 的信箱功能,只要去註冊一個信箱即可以使用,免費方案可以發送500封,這個信箱讓開發者很方便的測試發送信件,因為這信箱並不會真正的把信件寄出,寄出去的信件都會被放在你的信箱中,讓開發者很容易觀察寄出的信件內容是否正確。

註冊完後,會有一封信件指示告訴你該填入哪些資料,填寫完成後,就可以開始使用寄信功能,立馬測試一下忘記密碼功能。看看是否正確。

修改

參考 工程濕(X)筆記-改造 Laravel 忘記密碼功能 可以找到 寄送密碼重置信件是透過 User Model 的 sendPasswordResetNotification() ,所以在 User Model 下建立 sendPasswordResetNotification() 及 sendEmailVerificationNotification() 就可以覆寫掉 Laravel 內建的發信內容,改成自己定義的內容。

修改 config\auth.php,新增一段 重設密碼連結 reset_url 參數

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        //重設密碼連結
        'reset_url' => env('PASSSWORD_RESET_URL', 'https://localhost/password/reset/'),
    ],

sendPasswordResetNotification()

    //修改 寄出密碼重設通知
    public function sendPasswordResetNotification($token)
    {
        $notification = new ResetPasswordNotification($token);

        //使用 Illuminate\Auth\Notifications\ResetPassword 預留的 public static method toMailUsing()
        $notification::toMailUsing(function (User $notifiable, string $token) {
            // 建立「重設密碼」的 URL
            $passwordResetUrl = url(
                sprintf(config('auth.passwords.reset_url') . '%s?email=%s', $token, $notifiable->getEmailForPasswordReset())
            );

            // 重建 MailMessage
            // getFromJson 已在 v6 後併入 get() 須改用,並執行 php artisan view:clear 與 php artisan view:cache
            return (new MailMessage())
                    ->subject(Lang::get('Reset Password Notification'))
                    ->line(Lang::get('You are receiving this email because we received a password reset request for your account.'))
                    ->action(Lang::get('Reset Password'), $passwordResetUrl)
                    ->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.users.expire')]))
                    ->line(Lang::get('If you did not request a password reset, no further action is required.'));
        });

        // 依照原本的方式執行 notify
        $this->notify($notification);
    }

在註冊後寄送email驗證部份我採用建立一份新的 Notifications方式來達成,並從 vendor\laravel\framework\src\Illuminate\Auth\Notifications\VerifyEmail.php 中,將 via()、toMail() 及 verificationUrl() 三個 function 複製過來改寫。

php artisan make:notification App\Notifications\VerifyEmailNotification
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\URL;

class VerifyEmailNotification extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    //抓取註冊者信箱位置
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    //將內容送出
    public function toMail($notifiable)
    {
        $verificationUrl = $this->verificationUrl($notifiable);

        //修改信件內容
        return (new MailMessage)
            ->subject(Lang::get('Verify Email Address'))
            ->line(Lang::get('Please click the button below to verify your email address.'))
            ->action(Lang::get('Verify Email Address'), $verificationUrl)
            ->line(Lang::get('If you did not create an account, no further action is required.'));
    }

    /**
     * Get the verification URL for the given notifiable.
     *
     * @param  mixed  $notifiable
     * @return string
     */
    //獲取驗證Url
    protected function verificationUrl($notifiable)
    {
        return URL::temporarySignedRoute(
            'verification.verify',
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $notifiable->getKey(),
                'hash' => sha1($notifiable->getEmailForVerification()),
            ]
        );
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

回到 User Model 中,將新增的 Notification 導入

use App\Notifications\VerifyEmailNotification as VerifyEmailNotification;

修改 sendEmailVerificationNotification()

    //修改 寄出驗證信件通知
    public function sendEmailVerificationNotification()
    {
        $this->notify(new VerifyEmailNotification());
    }

語言包

由於測試站語言已經被設定成 zh-tw,加上上面覆寫 function 中使用 LANG 來做語言切換,只要去 larvel-lang/lang 安裝相對應版本的語言包,安裝完後,將 vendor/laravel-lang/lang/json 目錄下找出 zh-TW.json 檔案複製到 resources/lang 目錄下即可。

# 找出相對應 laravel 版本執行安裝
composer require laravel-lang/lang:~5.0

即使這樣還是會看到有一段英文,並沒有被轉譯,這是因為有一部分內容是已經在notifications 視圖中寫好的,沒法透過覆寫function去改變,但可將 notifications 視圖模板拉出來修改。

php artisan vendor:publish --tag=laravel-notifications
@lang(
    "If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
    'into your web browser:',
    [
        'actionText' => $actionText,
    ]
) <span class="break-all">[{{ $displayableActionUrl }}]({{ $actionUrl }})</span>

從這個 email.blade.php 視圖可以發現語言這段和語言包中的字串不相等所以造成沒有做翻譯,所以只要修改成和語言包一樣的字串,就會自己幫你轉成中文嚕

@lang("If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser: [:actionURL](:actionURL)")
最後修改日期: 2020 年 10 月 19 日