Table of Contents
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.
Leave a Reply