# Mail Bounce System Documentation ## Overview This system provides universal email bounce handling that works with any SMTP server by automatically intercepting all outgoing emails, checking for suppressed recipients, and processing bounce notifications from a dedicated mailbox. ## Key Features - **Universal Protection**: Automatically protects ALL mailables (newsletters, contact forms, notifications, etc.) - **SMTP Server Agnostic**: Works with any SMTP server that supports Return-Path headers - **Threshold-Based Suppression**: Conservative approach with configurable bounce thresholds - **Multi-Profile Support**: Handles Users, Organizations, Banks, and Admins - **Email Verification Management**: Resets verification status based on bounce patterns - **Comprehensive Logging**: Tracks all bounce processing and suppression actions ## How It Works 1. **Outgoing Emails**: All emails automatically get Return-Path and tracking headers 2. **Bounce Collection**: Bounces are sent to a dedicated mailbox (e.g., bounces@yourdomain.org) 3. **Bounce Processing**: System reads the mailbox and categorizes bounces (hard/soft/unknown) 4. **Threshold Checking**: Only definitive hard bounces count toward suppression thresholds 5. **Automatic Protection**: Suppressed emails are blocked from all future mailings ## Configuration Configure bounce thresholds in `config/timebank-cc.php` under `mailing.bounce_thresholds`: - **verification_reset_threshold**: Hard bounces before email_verified_at is reset (default: 2) - **suppression_threshold**: Hard bounces before email is suppressed (default: 3) - **counting_window_days**: Time window for counting bounces (default: 30 days) Configure automatic cleanup in `config/timebank-cc.php` under `mailing.bounce_thresholds.automatic_cleanup`: - **day_of_week**: Day for cleanup (0=Sunday, 1=Monday, etc.) (default: 1) - **time**: Time to run cleanup in 24-hour format (default: '03:00') - **cleanup_days**: Days after which to delete soft bounces (default: 90) - **cleanup_bounce_types**: Bounce types to cleanup, hard bounces are preserved (default: ['soft', 'unknown']) Set bounce mailbox in `.env`: - **BOUNCE_PROCESSING_ENABLED**: Enable/disable bounce processing (set to `false` on local/staging without IMAP) - **MAIL_BOUNCE_ADDRESS**: Return-Path address for bounces - **BOUNCE_MAILBOX**, **BOUNCE_HOST**, etc.: IMAP settings for bounce processing ## Artisan Commands ### Process Bounce Emails ```bash # Test bounce processing (dry run) php artisan mailings:process-bounces --dry-run # Process bounces and delete from mailbox php artisan mailings:process-bounces --delete # Process with custom mailbox settings php artisan mailings:process-bounces --mailbox=bounces@example.com --host=imap.example.com --username=bounces@example.com --password=secret --ssl --delete ``` ### Manage Bounced Emails ```bash # Show bounce statistics and threshold information php artisan mailings:manage-bounces stats # List all bounced emails php artisan mailings:manage-bounces list # Check bounce counts for specific email php artisan mailings:manage-bounces check-thresholds --email=user@example.com # Check all emails against thresholds php artisan mailings:manage-bounces check-thresholds # Manually suppress an email php artisan mailings:manage-bounces suppress --email=problem@example.com # Remove suppression from an email php artisan mailings:manage-bounces unsuppress --email=fixed@example.com # Clean up old soft bounces php artisan mailings:manage-bounces cleanup --days=90 ``` ### Simulate or process bounces — `bounce:simulate` Works in two modes depending on environment: **Inject mode** (local dev — no mailbox needed): ```bash # Check current state without recording php artisan bounce:simulate --email=user@example.com --status # Record a hard bounce (triggers threshold logic) php artisan bounce:simulate --email=user@example.com # Record a soft bounce (no threshold action) php artisan bounce:simulate --email=user@example.com --type=soft # Reset records between tests php artisan bounce:simulate --email=user@example.com --clear # Directly suppress without threshold logic php artisan bounce:simulate --email=user@example.com --suppress ``` **IMAP mode** (production — reads real bounce emails from `.env` mailbox): ```bash # Dry run: verify connection and parsing, record nothing php artisan bounce:simulate --imap --dry-run # Process and record all bounces found php artisan bounce:simulate --imap # Process, record, and clear mailbox php artisan bounce:simulate --imap --delete ``` Skips gracefully with a warning if IMAP credentials are not set in `.env`. See `references/BOUNCE_SIMULATE_COMMAND.md` for full documentation. ## Bounce Types - **Hard Bounce**: Permanent failure (user unknown, invalid domain) - counts toward thresholds - **Soft Bounce**: Temporary failure (mailbox full, server down) - recorded but ignored - **Unknown**: Unclassified bounces - recorded but ignored ## Threshold Actions Thresholds are configured in `config/timebank_cc.php` under `mailing.bounce_thresholds`. Current defaults: - **`verification_reset_threshold` hard bounces**: `email_verified_at` set to null for all profiles - **`suppression_threshold` hard bounces**: Email suppressed from all future mailings Only bounces matching a `definitive_hard_bounce_pattern` AND with type in `counted_bounce_types` count toward thresholds. ## Automatic Scheduling The system automatically schedules the following tasks in `app/Console/Kernel.php`: **Bounce Processing**: Every hour (only when `BOUNCE_PROCESSING_ENABLED=true`) ```php $schedule->command('mailings:process-bounces --delete') ->hourly() ->withoutOverlapping() ->when(fn() => config('app.bounce_processing_enabled', false)); ``` **Note**: Set `BOUNCE_PROCESSING_ENABLED=false` in `.env` on local development and staging environments to prevent IMAP connection errors. **Automatic Cleanup**: Configurable via `timebank-cc.php` config (default: Mondays at 3:00 AM) - Cleans up soft bounces older than the configured days (default: 90 days) - Preserves hard bounces for suppression decisions - Schedule automatically updates based on config settings ## Logging The system logs all bounce processing and suppression actions with "MAILING:" prefix in Laravel logs. Monitor logs to track system activity and troubleshoot issues.