ellite/Wallos · error · Exception

$this->lang('recipients_failed') . $errstr

Error message

$this->lang('recipients_failed') . $errstr

What it means

Thrown in smtpSend() after the DATA phase when one or more recipients were rejected by the server (collected in $bad_rcpt with their per-recipient SMTP errors). The exception message concatenates the localized 'recipients_failed' string with 'address: error' pairs. Unlike other SMTP errors this is STOP_CONTINUE, so per-recipient failures can still allow partial delivery to accepted recipients before the exception surfaces.

Solutions

  1. Read $mailer->ErrorInfo / the exception message: it lists each failed address with the server's error code.
  2. Validate recipient addresses before sending (filter_var($email, FILTER_VALIDATE_EMAIL), or verify the mailbox exists).
  3. Remove or correct rejected addresses from the recipient list and retry for the remaining recipients.
  4. If relay is denied (554/550 relay access denied), authenticate properly or use the correct relay host for external recipients.
  5. Check for typos and stale addresses in your mailing list source (hard bounces).

Example fix

// before
$mailer->addAddress('user@gmial.com'); // typo: rejected 550
$mailer->send();
// after
$rcpt = 'user@gmail.com';
if (filter_var($rcpt, FILTER_VALIDATE_EMAIL)) {
    $mailer->addAddress($rcpt);
}
$mailer->send();
Defensive patterns

Strategy: validation

Validate before calling

foreach ($recipients as $rcpt) {
    if (!filter_var($rcpt, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException("Invalid recipient: {$rcpt}");
    }
}

Try / catch

try {
    $mailer->send();
} catch (PHPMailer\PHPMailer\Exception $e) {
    if (str_contains($mailer->ErrorInfo, 'recipients_failed')) {
        error_log('Bad recipients: ' . $mailer->ErrorInfo); // lists address: error pairs
        // prune failed addresses from list and requeue remaining
    }
}

Prevention

When it happens

Trigger: Calling send() over SMTP when $this->smtp->recipient() returns false for any address during the RCPT TO loop: invalid/nonexistent recipient (550), relay denied (554), recipient over quota, or server rejecting due to rate/policy limits.

Common situations: Typo'd or bounce-hardened recipient addresses, sending to addresses that no longer exist, relaying denied for external recipients on an internal relay, distribution lists blocking external senders, per-recipient spam policies.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of ellite/Wallos@52820e87ca (2026-09-13). Data as JSON: /api/errors/00faff0086e5f6d4. Report an issue: GitHub.

Appendix: source

Thrown at libs/PHPMailer/PHPMailer.php:2086

            $this->doCallback(
                $cb['issent'],
                [[$cb['to'], $cb['name']]],
                [],
                [],
                $this->Subject,
                $body,
                $this->From,
                ['smtp_transaction_id' => $smtp_transaction_id]
            );
        }

        //Create error message for any bad addresses
        if (count($bad_rcpt) > 0) {
            $errstr = '';
            foreach ($bad_rcpt as $bad) {
                $errstr .= $bad['to'] . ': ' . $bad['error'];
            }
            throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
        }

        return true;
    }

    /**
     * Initiate a connection to an SMTP server.
     * Returns false if the operation failed.
     *
     * @param array $options An array of options compatible with stream_context_create()
     *
     * @throws Exception
     *
     * @uses \PHPMailer\PHPMailer\SMTP
     *
     * @return bool
     */
    public function smtpConnect($options = null)

View on GitHub (pinned to 52820e87ca)