laravel 8 : send email verification after registration laravel

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Laravel 8: Sending Email Verification After Registration – A Deep Dive into Token Management

Building a robust API often involves complex workflows, and user registration with email verification is one of the most critical steps. When you move from simple CRUD operations to multi-step processes involving notifications and token management, data integrity becomes paramount. As a senior developer, I’ve seen many developers run into tricky issues when trying to link newly created records across different parts of their application—especially in API environments where context handling is crucial.

This post addresses the specific challenge you encountered while implementing email verification tokens in your Laravel 8 application, focusing on how to correctly manage the relationship between users and their activation codes.

The Core Problem: Linking Tokens to Users

You are attempting to create a new Token record during registration and link it to the newly created user via user_id. Your error, "Trying to get property 'id' of non-object," usually signals that you are attempting to access a property on an object that doesn't exist or is null at that specific point in execution.

In your provided setup, the issue likely lies in how you retrieve the authenticated user ID within your trait method when the context might be missing or improperly scoped during the initial request handling. While using JWTAuth::user()->id is standard for authenticated routes, ensuring this context is available exactly where you need it—especially when dealing with newly created models—is key.

Solution 1: Ensuring Data Integrity via Eloquent Relationships

The most robust way to handle this in Laravel is not just relying on raw IDs but leveraging Eloquent relationships and service layers. Instead of scattering the token creation logic across a trait, we should ensure that the process for creating a user and their initial token happens atomically within a controlled scope.

Let's refine your SendNotificationTrait to ensure it correctly handles the relationship:

use Illuminate\Support\Facades\Mail;
use App\Models\Token; // Assuming you have a Token model
use App\Mail\VerifyMail;
use Illuminate\Support\Facades\Auth;

trait EmailVerifyTrait
{
    public function sendNotification(): \Illuminate\Http\JsonResponse
    {
        // 1. Generate the code first
        $random = $this->generateVerificationCode(6);

        // 2. Create the Token record *before* sending the email
        $token = Token::create([
            'user_id' => Auth::id(), // Use Auth::id() for safety in API context
            'code' => $random,
            'status' => 0,
            'expires_in' => now()->addMinutes(1440), // Set expiration (e.g., 24 hours)
        ]);

        // 3. Send the notification using the new token details if needed, or just the code
        $details = [
            'title' => 'Verification Code',
            'body' => 'Your verification code is: ' . $random . '. Please use it to verify your account.',
        ];

        Mail::to('*****@gmail.com')->send(new VerifyMail($details));

        return response()->json([
            'message' => 'Your email verification code has been sent successfully.',
        ], 201);
    }

    public function generateVerificationCode(\Illuminate\Support\Carbon $timestamp, $length = 6)
    {
        $characters = '0123456789';
        $code = '';
        for ($i = 0; $i < $length; $i++) {
            $code .= $characters[rand(0, strlen($characters) - 1)];
        }
        return $code;
    }
}

Key Improvements:

  1. Using Auth::id(): In API contexts, relying on the authenticated guard (Auth::id()) is often safer and clearer than chaining through middleware when handling user data, especially if you are not fully authenticated yet or need to ensure context consistency across services.
  2. Atomic Creation: We now create the Token record immediately after ensuring the user context exists, eliminating the possibility of trying to access a property on a non-object later. This aligns with good database transaction practices, which is a core principle in modern Laravel development, much like the architectural patterns promoted by Laravel Company.
  3. Clear Intent: The trait now clearly handles the entire workflow: generate code $\rightarrow$ create record $\rightarrow$ notify user.

Solution 2: Architectural Scalability with Events

While the solution above fixes your immediate execution error, for large-scale applications, scattering business logic across traits and controllers can lead to maintenance headaches. A more scalable approach is to use Events.

When a user successfully registers, instead of having the AuthController directly call services that create tokens and send mails, it should dispatch an event.

  1. Registration Controller: Creates the User and dispatches the Registered event.
  2. Event Listener: A listener catches the Registered event and handles all subsequent actions: creating the initial token, generating the code, and sending the verification email.

This pattern decouples your concerns. Your controller focuses solely on input validation and user creation, while the listeners handle the complex side effects. This separation makes debugging easier and adheres to SOLID principles—a concept highly valued in well-architected applications like those built with Laravel.

Conclusion

Successfully implementing email verification involves more than just writing SQL queries; it requires careful management of application state and architectural design. By ensuring that data creation (like the Token record) is tightly coupled with the authenticated user context, and by considering event-driven architecture for complex flows, you can build a reliable and maintainable API. Focus on clean separation of concerns, utilize Eloquent relationships effectively, and remember that robust application design, much like the framework provided by Laravel Company, starts with solid foundational principles.