Inadequate error handling with partial success to multiple recipients

Created on 13 August 2025, about 16 hours ago

Problem/Motivation

We send out email to multiple recipients via Mandrill/Mailchimp (for example when multiple people are subscribed to a thread or group). It could be a dozens or even a hundred people being sent the same email in a single API request.

If just one of those emails is rejected by the recipient (as spam), it gets logged as a failure, even though the email was successfully sent to the other 99 recipients.

In our Drupal code, we have no way of handling this because the Service::handleSendResponse() method only returns FALSE in all cases.

switch ($result->status) {
  case 'error':
  case 'invalid':
  case 'rejected':
    $to = $result->email ?? 'recipient';
    $status = $result->status ?? 'message';
    $error_message = $result->message ?? 'no message';
    if (!isset($result->message) && isset($result->reject_reason)) {
      $error_message = $result->reject_reason;
    }

    $this->log->error('Failed sending email from %from to %to. @status: @message', [
      '%from' => $message['from_email'],
      '%to' => $to,
      '@status' => $status,
      '@message' => $error_message,
    ]);
    return FALSE;

Steps to reproduce

You would need to send to multiple email addresses where one of them rejects it (or perhaps bounces it?).

Proposed resolution

Not sure of the best approach. Ideally the API itself would return individual results for each email address so the application can know which send failed and act accordingly.

In the short term I think handleSendResponse() and send() should return a more detailed error, for example, even if it said only what was in $response['status'] (error vs invalid vs rejected) and the message (which would tell us which email address had the error). Then we could use that information to mark that email address as not to be sent to in future by our system, or to retry sending this email only to that recipient and not all the others.

Remaining tasks

User interface changes

API changes

Data model changes

Feature request
Status

Active

Version

1.1

Component

Code

Created by

🇬🇧United Kingdom Rob230

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Rob230
  • 🇬🇧United Kingdom Rob230

    I don't actually know how to make this work, since the Drupal core MailInterface mail() returns a bool and only takes one argument that isn't passed by reference. There's no way to get this information out.

    I still don't think it makes sense for Service::handleSendResponse() to return FALSE in a loop. Potentially what happens is it queues multiple emails and logs each one as being queued, and then as soon as it encounters a rejected one, returns FALSE and acts like the whole thing was a failure (despite multiple emails being sent).

    What I was thinking is it should capture errors in an array, but don't return and keep looping. Then when the loop completes if $errors contains anything it can return false. But there's no way to surface these errors so I'm a bit stuck. I don't think the Drupal MailInterface was ever designed for sending to multiple recipients one at a time in a single operation.

    The only thing I can think of is to not treat "rejected" as an error at all. Technically Mailchimp tried, and no it wasn't successful but there's no point trying again. The rejection should be logged but it shouldn't be considered a failed send by the mail() function.

Production build 0.71.5 2024