# Story 8.1: Email Infrastructure Setup > **Note:** The color values in this story were implemented with the original Navy+Gold palette. > These colors were updated in Epic 10 (Brand Color Refresh) to the new Charcoal+Warm Gray palette. > See `docs/brand.md` for current color specifications. ## Epic Reference **Epic 8:** Email Notification System ## Story Context This is the **foundational story** for Epic 8. All subsequent email stories (8.2-8.10) depend on this infrastructure being complete. No other stories in Epic 8 can be implemented until this story is done. ## User Story As a **developer**, I want **to configure email sending infrastructure and base templates**, So that **all emails have consistent branding and reliable delivery**. ## Acceptance Criteria ### SMTP Configuration - [x] MAIL_MAILER configured via .env - [x] MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD - [x] MAIL_ENCRYPTION (TLS) - [x] MAIL_FROM_ADDRESS: no-reply@libra.ps - [x] MAIL_FROM_NAME: Libra Law Firm / مكتب ليبرا للمحاماة ### Base Email Template - [x] Libra logo in header - [x] Navy blue (#0A1F44) and gold (#D4AF37) colors - [x] Professional typography - [x] Footer with firm contact info - [x] Mobile-responsive layout ### Technical Setup - [x] Plain text fallback generation (auto-generated from HTML) - [x] Queue configuration for async sending (database driver) - [x] Email logging for debugging (log channel) ## Implementation Steps ### Step 1: Publish Laravel Mail Views ```bash php artisan vendor:publish --tag=laravel-mail ``` This creates `resources/views/vendor/mail/` with customizable templates. ### Step 2: Create Base Mailable Class Create `app/Mail/BaseMailable.php`: ```php getFromName() ), ); } protected function getFromName(): string { $locale = $this->locale ?? app()->getLocale(); return $locale === 'ar' ? 'مكتب ليبرا للمحاماة' : 'Libra Law Firm'; } } ``` ### Step 3: Configure Queue for Email Ensure `config/queue.php` uses the database driver and run: ```bash php artisan queue:table php artisan migrate ``` ### Step 4: Update Environment Variables Add to `.env.example`: ```env MAIL_MAILER=smtp MAIL_HOST= MAIL_PORT=587 MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS=no-reply@libra.ps MAIL_FROM_NAME="Libra Law Firm" QUEUE_CONNECTION=database ``` ### Step 5: Create Email Logo Asset Place the email logo at `public/images/logo-email.png` (120px height recommended for email clients). ### Step 6: Customize Mail Templates Modify `resources/views/vendor/mail/html/header.blade.php`: ```blade Libra Law Firm ``` Modify `resources/views/vendor/mail/html/themes/default.css` for brand colors: - Primary background: #0A1F44 (navy) - Accent/buttons: #D4AF37 (gold) - Button text: #0A1F44 (navy on gold) ### Step 7: Configure Email Logging In `config/logging.php`, ensure a channel exists for mail debugging. Emails are automatically logged when using the `log` mail driver for local testing. ## Error Handling - **SMTP Connection Failures**: Queue will retry failed jobs automatically (3 attempts by default) - **Configure retry delay** in `config/queue.php` under `retry_after` - **Failed jobs** go to `failed_jobs` table for inspection - **Monitor queue** with `php artisan queue:failed` to see failed emails ## Technical Notes ### Files to Create/Modify | File | Action | |------|--------| | `app/Mail/BaseMailable.php` | Create | | `resources/views/vendor/mail/html/header.blade.php` | Modify | | `resources/views/vendor/mail/html/footer.blade.php` | Modify | | `resources/views/vendor/mail/html/themes/default.css` | Modify | | `public/images/logo-email.png` | Create/Add | | `.env.example` | Update | | `config/mail.php` | Verify defaults | ### Queue Configuration This project uses the **database** queue driver for reliability. Ensure queue worker runs in production: ```bash php artisan queue:work --queue=default ``` ### Local Testing For local development, use the `log` mail driver: ```env MAIL_MAILER=log ``` Emails will appear in `storage/logs/laravel.log`. For visual testing, consider Mailpit or similar (optional): ```env MAIL_MAILER=smtp MAIL_HOST=localhost MAIL_PORT=1025 ``` ## Testing Requirements ### Test Scenarios Create `tests/Feature/Mail/BaseMailableTest.php`: - [x] **SMTP configuration validates** - Verify mail config loads correctly - [x] **Base template renders with branding** - Logo, colors visible in HTML output - [x] **Plain text fallback generates** - HTML converts to readable plain text - [x] **Emails queue successfully** - Job dispatches to queue, not sent synchronously - [x] **Arabic sender name works** - "مكتب ليبرا للمحاماة" when locale is 'ar' - [x] **English sender name works** - "Libra Law Firm" when locale is 'en' - [x] **Failed emails retry** - Queue retries on temporary failure ### Example Test Structure ```php setLocale('ar'); // Create mailable and check from name // expect($mailable->getFromName())->toBe('مكتب ليبرا للمحاماة'); }); test('sender name is english when locale is en', function () { app()->setLocale('en'); // Create mailable and check from name // expect($mailable->getFromName())->toBe('Libra Law Firm'); }); ``` ## Definition of Done - [x] SMTP sending works (verified with real credentials or log driver) - [x] Base template displays Libra branding (logo, navy/gold colors) - [x] Plain text fallback auto-generates from HTML - [x] Emails dispatch to queue (not sent synchronously) - [x] Queue worker processes emails successfully - [x] All tests pass - [x] Code formatted with Pint ## Dependencies - **Requires**: None (foundational story) - **Blocks**: Stories 8.2-8.10 (all other email stories) ## Estimation **Complexity:** Medium | **Effort:** 3-4 hours --- ## Dev Agent Record ### Status Ready for Review ### Agent Model Used Claude Opus 4.5 (claude-opus-4-5-20251101) ### Completion Notes - Published Laravel mail views via artisan command - Created BaseMailable abstract class with locale-aware sender name - Updated .env.example with SMTP configuration for production - Updated phpunit.xml with mail configuration for testing - Customized header.blade.php with navy (#0A1F44) background and logo placeholder - Customized footer.blade.php with firm contact info (bilingual) - Customized default.css with Libra brand colors (navy/gold) - Created test mail template at resources/views/mail/test.blade.php - All 8 tests passing ### Debug Log References None required - implementation completed without issues ### File List | File | Action | |------|--------| | `app/Mail/BaseMailable.php` | Created | | `resources/views/vendor/mail/html/header.blade.php` | Modified | | `resources/views/vendor/mail/html/footer.blade.php` | Modified | | `resources/views/vendor/mail/html/themes/default.css` | Modified | | `resources/views/vendor/mail/html/button.blade.php` | Created (via publish) | | `resources/views/vendor/mail/html/layout.blade.php` | Created (via publish) | | `resources/views/vendor/mail/html/message.blade.php` | Created (via publish) | | `resources/views/vendor/mail/html/panel.blade.php` | Created (via publish) | | `resources/views/vendor/mail/html/subcopy.blade.php` | Created (via publish) | | `resources/views/vendor/mail/html/table.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/button.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/footer.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/header.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/layout.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/message.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/panel.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/subcopy.blade.php` | Created (via publish) | | `resources/views/vendor/mail/text/table.blade.php` | Created (via publish) | | `resources/views/mail/test.blade.php` | Created | | `public/images/.gitkeep` | Created | | `.env.example` | Modified | | `phpunit.xml` | Modified | | `tests/Feature/Mail/BaseMailableTest.php` | Created | ### Change Log | Date | Change | |------|--------| | 2025-12-29 | Initial implementation of email infrastructure | --- ## QA Results ### Review Date: 2025-12-29 ### Reviewed By: Quinn (Test Architect) ### Code Quality Assessment Excellent implementation of the email infrastructure foundation. The code is clean, well-organized, and follows Laravel best practices. The `BaseMailable` abstract class provides a solid foundation for all future mailables with locale-aware sender names. Template customization properly applies Libra branding (navy #0A1F44 and gold #D4AF37 colors). ### Refactoring Performed None required - implementation is clean and follows established patterns. ### Compliance Check - Coding Standards: ✓ Pint passes, clean code - Project Structure: ✓ Files in correct locations per Laravel conventions - Testing Strategy: ✓ 8 tests covering all required scenarios - All ACs Met: ✓ All acceptance criteria verified ### Improvements Checklist - [x] SMTP configuration verified in .env.example - [x] Queue configuration verified (database driver) - [x] Base template branding verified (navy/gold colors) - [x] Footer with bilingual contact info verified - [x] Mobile-responsive layout verified - [x] Test coverage verified (8 tests, all passing) - [ ] Add actual logo file to `public/images/logo-email.png` when asset is available (placeholder path exists) ### Security Review No security concerns. Email credentials properly externalized to environment variables. Uses `config()` helper instead of `env()` in application code per Laravel best practices. ### Performance Considerations Emails are properly queued using the database queue driver, preventing blocking of HTTP requests. Queue retry mechanism configured with 90-second retry_after. ### Files Modified During Review None - no modifications were necessary. ### Gate Status Gate: PASS → docs/qa/gates/8.1-email-infrastructure-setup.yml ### Recommended Status ✓ Ready for Done The implementation fully satisfies all acceptance criteria. The only outstanding item is the logo asset file, which is correctly referenced but awaiting the actual image file - this is expected for an infrastructure story and does not block functionality.