Table of Contents
Refactoring email templates is risky. One typo and your production emails break. Here’s how to iterate safely with side-by-side comparisons.
The Pattern
When you need to redesign an email template:
- Duplicate the template with
-oldsuffix - Create test routes for both versions
- Modify the new version while keeping old as reference
- Compare side-by-side before committing
Step 1: Duplicate Templates
cd resources/views/emails
cp notification.blade.php notification-old.blade.php
Now you have:
notification.blade.php— Your working copy (will be modified)notification-old.blade.php— Backup (unchanged)
Step 2: Create Test Routes for Both
// routes/web.php (local/testing only)
Route::get('/test/email/notification-old', function () {
$request = App\Models\Request::factory()->make();
return (new App\Mail\RequestNotification($request))
->render('emails.notification-old');
});
Route::get('/test/email/notification-new', function () {
$request = App\Models\Request::factory()->make();
return new App\Mail\RequestNotification($request);
});
If your mailable uses a hardcoded view name, override it in the route:
Route::get('/test/email/notification-old', function () {
$mailable = new App\Mail\RequestNotification($request);
$mailable->view = 'emails.notification-old'; // Override
return $mailable;
});
Step 3: Iterate on the New Version
Edit notification.blade.php freely. After each change:
- Open
/test/email/notification-old(baseline) - Open
/test/email/notification-new(your changes) - Compare side-by-side
If something breaks, the old version is still rendering correctly for comparison.
Step 4: Add State Parameters
Support different email states in both routes:
Route::get('/test/email/notification-old', function (Request $request) {
$status = $request->get('status', 'pending');
$requestModel = App\Models\Request::factory()->make(['status' => $status]);
$mailable = new App\Mail\RequestNotification($requestModel);
$mailable->view = 'emails.notification-old';
return $mailable;
});
Route::get('/test/email/notification-new', function (Request $request) {
$status = $request->get('status', 'pending');
$requestModel = App\Models\Request::factory()->make(['status' => $status]);
return new App\Mail\RequestNotification($requestModel);
});
Now compare all states:
/test/email/notification-old?status=pendingvs/test/email/notification-new?status=pending/test/email/notification-old?status=approvedvs/test/email/notification-new?status=approved/test/email/notification-old?status=rejectedvs/test/email/notification-new?status=rejected
When to Commit
Once the new version looks good across all states:
- Delete
notification-old.blade.php - Delete the test routes
- Commit
notification.blade.php
The -old backup stays in git history if you need it later.
Why This Works
- Safe iteration — Original always accessible for comparison
- Visual confirmation — See exactly what changed
- Catch regressions — Spot broken states before prod
- Fast rollback — Just restore the
-oldfile if needed
Bonus: Use Browser DevTools to Compare
Open both URLs in separate browser tabs. Use DevTools to inspect HTML structure and spot differences. Chrome’s “Compare” feature in Elements panel is especially useful.
This pattern works for any high-stakes template refactor—emails, PDFs, invoices, reports. Duplicate, compare, commit.
Leave a Reply