5

I'm looking to send personalised batch e-mails to a large number of users. By this I mean that I would like to set up a template e-mail and inject each user's information into it before sending it.

Of course, this can easily be achieved with Laravel by looping through user data and using the Mailer (Or Mail facade) methods (Such as send, raw, queue etc.):

foreach ($users as $user) {
    $data = ['user' => $user];
    $this->mailer->queue($views, $data, function($message) use($user) {
        $message->to($user->email, $user->name);
    });
}

However, considering the volume of e-mails I would like to send, this would be far too slow for my needs. After some research I have discovered that Mailgun supports sending personalised batch e-mails using their API. From their website:

Batch sending

With a single API call, you can send up to 1000 fully personalized emails.

Mailgun will properly assemble the MIME message and send the email to each of your users individually. That makes sending large volumes of email a lot faster and a lot less resource intensive.

  • I was wondering if Laravel supports personalised batch e-mail sending in this way? I haven't managed to find anything in the documentation or the code to support this.
  • Are there any existing packages available for Laravel to support this?

Of course, I could happily implement this using Mailgun's API directly or using any available SDKs, but just wanted to check to see if it is supported by Laravel first.

Community
  • 1
  • 1
Jonathon
  • 15,873
  • 11
  • 73
  • 92
  • I was looking for this same thing a few months back and couldn't find any ready made solution, so I ended up writing the function myself. It's really simple though using the Mailgun batches. – Rolf Pedro Ernst Aug 03 '16 at 12:39
  • Thanks for your reply. That's a shame. Would you mind posting an answer and potentially include how you achieved it? I can accept if I don't get any more responses. – Jonathon Aug 03 '16 at 13:40
  • I'm using [Swiftmailer Mailgun bundle](https://github.com/tehplague/swiftmailer-mailgun-bundle) with [Sending Emails in Batch with swiftmailer](http://swiftmailer.org/docs/sending.html#sending-emails-in-batch) for such thing in my Symfony apps. If you can use this bundle in your Laravel app, you shouldn't look any further. – BentCoder Aug 03 '16 at 14:15

2 Answers2

4

Here's how I solved an identical situation since I couldn't find any ready made solution.

        $subscribers = Subscriber::active()->get();
        $batch = 0;
        $batch_subscribers = array();
        $batch_subscribers_data = array();
        foreach ($subscribers as $subscriber)
        {
            $batch_subscribers[] = $subscriber->mail;
            $batch_subscribers_data[$subscriber->mail] = array(
                "id" => $subscriber->id,
                "mail" => $subscriber->mail,
                "name" => $subscriber->name
            );
            $batch++;
            if($batch < 999){
                continue;
            }
            $input['to'] = $batch_subscribers;
            $input['vars'] = $batch_subscribers_data;
            Mailgun::send('email/email-base', ['input' => $input],
                function ($message) use ($input) 
                {
                    $message->subject($input['asunto']);
                    $message->to($input['to']);
                    $message->replyTo("reply@address.com");
                    $message->recipientVariables($input['vars']);
                });
            $batch_subscribers = array();
            $batch_subscribers_data = array();
            $batch = 0;
        }
0

To anybody who still wants to use Laravel Mailable,

you can override the Mailgun transport class to tweak the payload:

  /**
   * Get the HTTP payload for sending the Mailgun message.
   *
   * @param  \Swift_Mime_SimpleMessage  $message
   * @param  string  $to
   * @return array
   */
  protected function payload(Swift_Mime_SimpleMessage $message, $to)
  {
    // use laravel official mailgun transport when
    // batch_sending in config not set, or
    // only 1 recipient
    if (! $this->batchSending || count($message->getTo()) === 1) {
      return parent::payload($message, $to);
    }

    // batch sending
    $ret = [
      'auth' => [
        'api',
        $this->key,
      ],
      'multipart' => [
        [
          'name' => 'message',
          'contents' => str_replace(
            $message->getHeaders()->get('to')->toString(),
            'To: %recipient%'.PHP_EOL,
            $message->toString()
          ),
          'filename' => 'message.mime',
        ],
      ],
    ];

    $recipients = [];
    foreach ($message->getTo() as $address => $name) {
      $ret['multipart'][] = [
        'name' => 'to',
        'contents' => "$name <$address>",
      ];

      $recipients[$address] = [
        'name' => $name,
      ];
    }

    $ret['multipart'][] = [
      'name' => 'recipient-variables',
      'contents' => json_encode($recipients),
    ];

    return $ret;
  }

I just created a package https://github.com/leondeng/laravel-batch-mailgun for this, please have a try and feedback me if any issue, thanks!

ImLeo
  • 991
  • 10
  • 17