When the user registers, an email will be sent to confirmation
But how do I send a notification when a user updates their email?
Like when he registers
Use the link below to use Laravel's own verification system
ANSWER 2024/4/8
important: This method does not use MustVerifyEmail
In the future, I will write the method of using MustVerifyEmail
as an update here
Use the link below to use Laravel's own verification system https://laravel.com/docs/11.x/verification
SUMMARY SAMPLE:
This link explains about it https://laravel.com/docs/11.x/mail
For testing, you can set the value of MAIL_MAILER
to log
in .env
to see when the email is sent in /storage/log/laravel.log.
A simple example, without the need for a package, for the user to receive a link for confirmation after changing the email, we can proceed like this:
In routes/web.php
<?php
use App\Mail\EmailConfirmation;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Route;
Route::middleware('auth')->group(function(){
Route::get('change-email', function(){
$email = Auth::user()->email;
return view('change-email', compact('email'));
})->name('change-email');
Route::post('change-email-post', function(Request $request)
{
$validatedData = $request->validate([
'email' => 'required|email',
]);
$updated = User::where(['id' => Auth::id()])->update($validatedData);
if($updated) {
$key = setVerifyToken($validatedData['email']);
$link = route('verify', ['key' => $key]);
Mail::to(Auth::user())->send(new EmailConfirmation(Auth::user(), $link));
session()->flash('message', 'Your email is update, please check your inbox to confirm the new email');
} else {
session()->flash('message', 'Cannot update your email, try again after 60 seconds');
}
return redirect()->route('change-email', ['email' => $validatedData['email']]);
})->name('change-email-post');
});
Route::get('verify/{key}', function($key){
$email = getVerifyValue($key, $state);
if(! $state) {
$message = $email;
} else {
$user = User::where(['email' => $email, 'email_verified_at' => null])->update([
'email_verified_at' => Carbon::now(),
]);
if($user) {
$message = "Email is verified";
} else {
$message = "Unverified user not found";
}
}
return view('verify', compact('message'));
})->name('verify');
The change-email
path is used to display the form
The change-email-post
route is used to send confirmation emails and email updates
The verify path
is used to verify the email.
Then it is better to create a helper for ease of work
Of course, you can define functions wherever you want.هد
In composer.json
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
},
"files": [
"app\\helpers.php"
]
},
Then create the app/helpers.php
file
Then type the following command:
composer dump-autoload
Then create the app/helpers.php file
In app/helpers.php
<?php
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
if(! function_exists('setVerifyToken')) {
function setVerifyToken($account){
// '<str>' skeleton key
// '<email>:<expire link>'
$key = base64_encode(Hash::make(Str::random(30).$account));
$expire = time() + 600; // 10 minute
Cache::put($key, $account.':'.$expire);
return $key;
}
}
if(! function_exists('getVerifyValue')) {
function getVerifyValue(string $key, &$state) {
if(! Cache::has($key)) {
$state = false;
return "key not found";
}
[$email, $expire] = explode(':', Cache::get($key));
if($expire < time()) {
$state = false;
return "key is expired"; //expired
}
$state = true;
return $email;
}
}
The setVerifyToken()
function creates a hash for us using Hash::make
and creates a string, the first part of which is 30 random characters and the second part of the requested account string, so that the probability of two similar links for two different emails interfering is close to zero. reach it
After caching it, it returns the value of $key
, which can be used to reset and confirm the correctness of $key
using the getVerifyValue()
function.
We can use mail to send email
php artisan make:mail EmailConfirmation
In app/Mail/EmailConfirmation.php
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class EmailConfirmation extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(public User $user, public $link)
{
//
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
from: config('mail.from.address'),
subject: 'Email Confirmation',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'email-confirmation',
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
And then making blade templates;
In resources/views/change-email.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="POST" action="{{ route('change-email-post') }}">
@csrf
<input name="email" value="{{ $email }}" type="email">
<button type="submit">update</button>
@if(session()->has('message'))
<li>{{session()->get('message')}}</li>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
</form>
</body>
</html>
In resources/views/email-confirmation.blade.php
Hello {{ $user->name }}
Your {{ $user->email }} email needs confirmation
Please confirm your link by clicking on the link below
{{ $link }}
In resources/views/verify.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
{{ $message }};
</body>
</html>
Now we run the php artisan optimize:clear
and php artisan optimize
commands