Test Routes for Email Template Development

📖 2 minutes read

Stop sending test emails or checking mail catches every time you tweak an email design. Create test routes that render your templates instantly in the browser.

The Pattern

Add temporary routes to your web.php that return your mailable’s rendered view:

// routes/web.php (or separate routes/testing.php)

Route::get('/test/email/notification', function () {
    $request = App\Models\Request::factory()->make([
        'status' => 'pending',
        'customer_name' => 'Jane Smith',
        'product_name' => 'Monthly Subscription',
    ]);

    return new App\Mail\RequestNotification($request);
});

Hit http://yourdomain.test/test/email/notification in your browser—instant preview.

Support Multiple States

Emails often have different layouts based on status (pending, approved, rejected). Use a query parameter to switch between them:

Route::get('/test/email/notification', function (Request $request) {
    $status = $request->get('status', 'pending');
    
    $requestModel = App\Models\Request::factory()->make([
        'status' => $status,
        'customer_name' => 'Jane Smith',
        'product_name' => 'Monthly Subscription',
    ]);

    return new App\Mail\RequestNotification($requestModel);
});

Now you can preview:

  • /test/email/notification?status=pending
  • /test/email/notification?status=approved
  • /test/email/notification?status=rejected

Use Factory States for Realistic Data

If your factories have states for edge cases, use them:

Route::get('/test/email/notification', function (Request $request) {
    $status = $request->get('status', 'pending');
    
    $requestModel = match ($status) {
        'approved' => App\Models\Request::factory()->approved()->make(),
        'rejected' => App\Models\Request::factory()->rejected()->make(),
        'pending' => App\Models\Request::factory()->pending()->make(),
        default => App\Models\Request::factory()->make(['status' => $status]),
    };

    return new App\Mail\RequestNotification($requestModel);
});

Protect These Routes

Don’t let test routes hit production. Options:

1. Environment check in route file

if (app()->environment('local', 'testing')) {
    Route::get('/test/email/notification', ...);
}

2. Separate route file loaded conditionally

// bootstrap/app.php
if (app()->environment('local', 'testing')) {
    app()->booted(function () {
        require base_path('routes/testing.php');
    });
}

3. Middleware guard

Route::middleware(['env:local'])->group(function () {
    Route::get('/test/email/notification', ...);
});

Why This Helps

  • Instant feedback — No mail queue delays
  • State switching — Preview all variations quickly
  • Designer-friendly — Share URLs for design review
  • Regression testing — Check old templates after refactors

Once you’re done iterating, delete the routes. They’re scaffolding, not production code.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *