Skip to content

Record bounces delivered to group addresses, not just bounce- addresses #39

@edwh

Description

@edwh

Problem

When an email we send bounces, the DSN (Delivery Status Notification) is normally returned to the bounce-{userid}-{timestamp}@users.ilovefreegle.org Return-Path. The bounce handler extracts the user ID from this address and records the bounce against the user's email.

However, some bounces are delivered to group addresses instead (e.g. Bexhillfreegle-auto@groups.ilovefreegle.org). This happens when the original email was sent from a group address rather than a bounce address. These bounces are correctly parsed as DSNs (we extract the bounced recipient and status code), but the bounce is never recorded because handleBounce() only extracts user IDs from bounce-{userid}- formatted addresses.

Example from production (2026-02-02)

  • DSN from Outlook to Bexhillfreegle-auto@groups.ilovefreegle.org
  • Bounce recipient: jo699@msn.com (5.2.2 mailbox full)
  • Permanent bounce, but never recorded — user keeps getting emails that bounce

Legacy behaviour

The legacy Exim/PHP system has the same gap. Bounce::process() in include/mail/Bounce.php line 73 only matches bounce-{userid}- addresses, so group-addressed bounces are saved to the bounces table but never processed.

Proposed fix

In IncomingMailService::handleBounce(), when the envelope-to doesn't match bounce-{userid}-, fall back to looking up the bounce recipient email directly in users_emails:

// Current: only records bounce if envelope-to is bounce-{userid}-...
if (preg_match('/^bounce-(\d+)-/', $localPart, $matches)) {
    $userId = (int) $matches[1];
    if ($email->isPermanentBounce() && $email->bounceRecipient) {
        $this->recordBounce($userId, $email->bounceRecipient);
    }
}

// Proposed addition: if no bounce address, look up recipient directly
if (!isset($userId) && $email->isPermanentBounce() && $email->bounceRecipient) {
    $userEmail = UserEmail::where('email', $email->bounceRecipient)->first();
    if ($userEmail) {
        $this->recordBounce($userEmail->userid, $email->bounceRecipient);
    }
}

Files

  • iznik-batch/app/Services/Mail/Incoming/IncomingMailService.phphandleBounce() method
  • Tests in iznik-batch/tests/Unit/Services/Mail/Incoming/IncomingMailServiceTest.php

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions