Cakephp 4 Mailer

Hello, everyone. I have a question about using the Cake Mailer to send to multiple recipients. Ideally, I would like each recipient to receive their own, individually-addressed email. In Cake 2, this was just a matter of looping through the to() and send() methods. The only way I’ve found to do it in Cake 4 is through the controller:

foreach($toArray as $t) {
    $this->getMailer('Mailer')->send('newMail', [$fulltitle, $t->email, $t->first_name]);
}

When I attempt the loop within the mailer itself, only the final recipient gets the message:

// Call Mailer in controller. Like above, but without the loop and passing the entire $toArray
$this->getMailer('Mailer')->send('newMail', [$fulltitle, $toArray]);


// newMail method in Mailer
public function newMail($fulltitle, $toArray)
{ 
    foreach ($toArray as $t) { 
        $this
        ->setEmailFormat('html')
        ->setTo($t->email)
        ->setFrom(['dba@whereiwork.org' => 'DBA'])
        ->setSubject(sprintf($fulltitle . " is ready for review"))
        ->setViewVars([
            'first_name' => $t->first_name,
            'fulltitle' => $fulltitle,
        ])
        ->viewBuilder()
            ->setTemplate('new_mail') 
            ->setLayout('default');
    }
}

So, if I have an array of, say, three email addresses, only the last one gets mailed. Is there a way to do this in the mailer itself, or am I stuck doing it in the controller (not my preference)?

This is because your newMail() method is configuring the Mail object which is being returned to the send() method to be sent.

So, your send is waiting patiently while the object is configured in different ways, then it acts on the final configuration.

You could make a new class that has a method that accepts an array of recipients, then loops through then configuring and sending each email in turn; an extension of Mail perhaps.

I’m not sure if I explained that well…

Essentially,

$this->getMailer('Mailer')->send('newMail', [$fulltitle, $toArray]) says pass the result of newMail to send.

Ah, gotcha. Makes perfect sense after looking at the code again. :smiley:

For now, I think I’ll just drop the mailer in its own method in the same controller. It’s going to be used in several different parts of my app, and having a one-stop for it will be nice & tidy. Thanks!

Instead of dropping it in it’s own controller, you could slap it into either a component or it’s own standalone class (a regular PHP class).

What you could also do is use the email class:

// Set the recipients
$recipients = ['alice@example.com', 'bob@example.com', 'j.doe@example.com'];

// An array to hold our results
$results = [];

// Loop over all recipients and send em our spam... I mean mail.
foreach($recipients as $recipient):
  $mail = new \Cake\Mailer\Mailer();
  $mail->setTo($recipient);
  // ... Do more stuff you please here
  $results[$recipient] = $mail->deliver();
endforeach;

// ... Process the results here

Just going back to a more “basic” OOP :slight_smile: