libra/docs/stories/story-8.1-email-infrastruct...

6.7 KiB

Story 8.1: Email Infrastructure Setup

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

  • MAIL_MAILER configured via .env
  • MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD
  • MAIL_ENCRYPTION (TLS)
  • MAIL_FROM_ADDRESS: no-reply@libra.ps
  • MAIL_FROM_NAME: Libra Law Firm / مكتب ليبرا للمحاماة

Base Email Template

  • Libra logo in header
  • Navy blue (#0A1F44) and gold (#D4AF37) colors
  • Professional typography
  • Footer with firm contact info
  • Mobile-responsive layout

Technical Setup

  • Plain text fallback generation (auto-generated from HTML)
  • Queue configuration for async sending (database driver)
  • Email logging for debugging (log channel)

Implementation Steps

Step 1: Publish Laravel Mail Views

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

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

abstract class BaseMailable extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;

    public function envelope(): Envelope
    {
        return new Envelope(
            from: new \Illuminate\Mail\Mailables\Address(
                config('mail.from.address'),
                $this->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:

php artisan queue:table
php artisan migrate

Step 4: Update Environment Variables

Add to .env.example:

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:

<tr>
    <td class="header" style="background-color: #0A1F44; padding: 25px; text-align: center;">
        <a href="{{ config('app.url') }}" style="display: inline-block;">
            <img src="{{ asset('images/logo-email.png') }}" alt="Libra Law Firm" height="45" style="height: 45px;">
        </a>
    </td>
</tr>

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:

php artisan queue:work --queue=default

Local Testing

For local development, use the log mail driver:

MAIL_MAILER=log

Emails will appear in storage/logs/laravel.log.

For visual testing, consider Mailpit or similar (optional):

MAIL_MAILER=smtp
MAIL_HOST=localhost
MAIL_PORT=1025

Testing Requirements

Test Scenarios

Create tests/Feature/Mail/BaseMailableTest.php:

  • SMTP configuration validates - Verify mail config loads correctly
  • Base template renders with branding - Logo, colors visible in HTML output
  • Plain text fallback generates - HTML converts to readable plain text
  • Emails queue successfully - Job dispatches to queue, not sent synchronously
  • Arabic sender name works - "مكتب ليبرا للمحاماة" when locale is 'ar'
  • English sender name works - "Libra Law Firm" when locale is 'en'
  • Failed emails retry - Queue retries on temporary failure

Example Test Structure

<?php

use App\Mail\BaseMailable;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;

test('emails are queued not sent synchronously', function () {
    Queue::fake();

    // Send a test email extending BaseMailable
    // Assert job was pushed to queue
});

test('sender name is arabic when locale is ar', function () {
    app()->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

  • SMTP sending works (verified with real credentials or log driver)
  • Base template displays Libra branding (logo, navy/gold colors)
  • Plain text fallback auto-generates from HTML
  • Emails dispatch to queue (not sent synchronously)
  • Queue worker processes emails successfully
  • All tests pass
  • 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