Blog

How to set up batch emails

Agathe Agathe
· 11 min read · New features and updates · March 4th, 2022
Transactional emails are sent immediately when they’re triggered by recipients, but sometimes a scheduled email delivery is preferred to synchronize it with an event. Learn how to set up batch email (+ download a sample code).

Transactional emails, like password resets and order confirmations, are typically sent as soon as they are triggered by recipients. This is great for time-sensitive situations where speedy email delivery gives peace of mind and reassurance.

At other times, when recipients share the same transaction, a delayed delivery can be preferred. For example, if people have signed up to receive product updates and you wish to notify all of them at once whenever a new app version is released.

You can set up batch email sending using MailerSend’s send bulk emails endpoint

Learn how to delay sending email by working with an example using the MailerSend PHP library, then download the sample code to help you get started!

What is batch email?

In transactional sending, batch emails are emails sent to recipients who perform a common action, for example, signing up for an event. They are sent in batches for optimal email deliverability and to avoid overloading email servers. You may have heard them referred to as bulk emails or blast emails.

Note: Bulk emails are also used in email marketing where promotional email campaigns are sent in very large volumes. Subscribers to these emails have opted-in to receive marketing emails and their contents usually contain a call to action.

How do you send a batch email?

The best way to send batch or bulk email is with a reliable email service provider. Doing so will enable you to send higher volumes of email and ensure maximum deliverability. You’ll also be able to easily segment the desired recipients, schedule the email to go out at the right time, and monitor the performance of the email with real-time engagement metrics (such as open rate and click-through rate). 

For example, in MailerSend the bulk email functionality enables you to send a single email to many recipients. You can use the endpoint by including it in a POST request like this:

POST https://api.mailersend.com/v1/bulk-email

If you’re on a Free or Premium plan, you can include 500 individual email objects in a single request, each containing up to 50 TO recipients, 10 CC, and 10 BCC, for a total of 35,000 emails. Otherwise, you are limited to 5 individual email objects.

For speedy sendings and to save you time, bulk emails are sent asynchronously without waiting for an API response. Email validation is also done after the request. You can check for failed emails and validation errors using the bulkemailid in a GET request:

GET https://api.mailersend.com/v1/bulk-email/{bulk_email_id}

How to send batch emails in PHP

Here’s an example to help you get started sending batch emails in MailerSend. Let’s say that you’re organizing an event and you want to follow up with everyone who signed up for it. An email reminder will be sent, along with the event schedule as a PDF file, to everyone a few days before the event.

A general workflow to send email notifications:

1. Identify the event and guests that you need to send a reminder to

2. Prepare an email message for each guest

3. Schedule emails to send later using a bulk request

The email reminders are sent using the MailerSend PHP SDK, where a cron job will call the PHP routine every minute. Let’s see how you can set up all this in 5 steps!

Note: PHP is used as an example since it’s one of the easiest scripting languages. If you prefer using another programming language, learn how to send emails using other MailerSend SDKs.

1. Set up the database structure

Start by organizing your event data into tables using the following database schema:

  • The events table stores the event name, event date, and the date and time we want to send the email reminders to our guests

  • The guests table contains the guest’s name, email address, the ID of the event that the guest belongs to, and a flag indicating whether a reminder was sent

database schema example
Note: The events table has a one-to-many relationship with guests as one event can have many guests attending it.

2. Create an email template

Compose the email reminder template in MailerSend using the drag & drop template builder. You can also use the rich-text email editor or create a custom design with the HTML editor.

create an email template in mailersend

Each email template will contain the following variables for simple personalization:

  • {$guest_name}, the name of the guest

  • {$event_name}, the name of our event

  • {$date}, the date of the event in the format Month Xth (e.g. October 1st)

  • {$time}, the time of the event in 12-hour format (e.g. 1:00pm)

The email subject line is also customized with the following variables:

  • {$event_name}, the name of the event

  • {$days_left}, how many days are left for the event

  • {$days_label}, which is “days” if the event is more than 1 day away or “day” if the event is tomorrow

Now that you have everything in place to start sending email reminders, let’s get coding!

3. Collect all the relevant information

Use the following PHP code to make an SQL-like query to your database. This will select the guests to the event to whom you haven’t sent a reminder.

/**
* Collect the guest and event information to send the reminder to
* We access the database using Illuminate but you can use whatever you want.
* The following is equivalent to this SQL query:
*
* SELECT guests.*, events.event_name, events.data FROM guests JOIN events ON events.id = guests.event_id
* WHERE guests.reminded = 0 AND events.remind_date <= NOW();
*/
$guestReminders = DB::table('guests')->select(['guests.*', 'events.event_name', 'events.date'])
   ->join('events', 'events.id', '=', 'guests.event_id')
   ->where('guests.reminded', '=', '0')
   ->where('events.remind_date', '<=', 'NOW()')
   ->get();

4. Prepare the email for each guest

To prepare the emails for sending, store each one in an array that you’ll use to make a bulk email request. Guest IDs are stored so you can keep track of which guests you have sent a reminder to. Also, the code is smart enough to know how many day(s) are left until the event, producing a grammatically correct subject line!

// we'll store the emails we want to send in an array that we'll use in the bulk email request
$emails = [];

// we'll store the guest ids so that we can update the ones we sent the reminder to
$sentToGuestIds = [];

// we loop through the collected database records to set up the recipients and variables
foreach ($guestReminders as $guestReminder) {

   $eventDate = DateTime::createFromFormat('Y-m-d H:i:s', $guestReminder->date);
   $currentDate = new DateTime();

   // we want to use a subject like "X days left for our event",
   // so we calculate the number of days between the event data and now
   $daysLeft = $currentDate->diff($eventDate);
   $daysLeft = (int)($daysLeft->days + ceil($daysLeft->h / 24));

   $recipients = [
       new Recipient($guestReminder->email, $guestReminder->name)
   ];

   // if the event is 1 day away, we don't want the subject to be '1 days left for the our event'
   // so we use a label for the word "days" which we change to "day" if the event is 1 day away
   $daysLabel = 'days';
   if ($daysLeft == 1) {

       $daysLabel = 'day';
   }

   // we set up the variables for our email
   $variables = [
       new Variable($guestReminder->email, [
           'guest_name' => $guestReminder->name,
           'event_name' => $guestReminder->event_name,
           'date' => $eventDate->format('F jS'),
           'time' => $eventDate->format('g:ia'),
           'days_left' => (string)$daysLeft,
           'days_label' => $daysLabel
       ])
   ];

   // set up the email
   $email = (new EmailParams())
       ->setFrom('your from email address')
       ->setFromName('your from name')
       ->setRecipients($recipients)
       ->setSubject('Only {$days_left} {$days_label} left for {$event_name}!')
       ->setTemplateId('your template id')
       ->setVariables($variables);

   // if we want to also include the event schedule, we can do the following:
   /*
       $attachments = [
           new Attachment(file_get_contents('schedule.pdf'), 'schedule.pdf')
       ];

       $email->setAttachments($attachments);
   */

   $emails[] = $email;

   // we store the id of each guest we sent the reminder to so that we can update its "reminded" field.
   // that way we prevent sending duplicate reminders to the guests
   $sentToGuestIds[] = $guestReminder->id;

   // there is a limit of 500 emails per bulk request, so if we reach 500 emails,
   // we need to break to send the emails we prepared and continue in the next run
   if (count($emails) == 500) {

       break;
   }
}
Note: As seen in the code comments above, the event schedule can be attached as a PDF file named schedule.pdf. Simply uncomment the code to enable file attachments.

5. Send using the bulk email endpoint

Before sending, check if there are any emails left to send using the following PHP routine. If so, the bulk-email endpoint will be called using your MailerSend API token. Once sent, the reminder flag will be updated to show that an email has been sent.

// we check that we have emails to send and then do a request to the bulk email MailerSend endpoint
if (count($emails) > 0) {

   // init the MailerSend SDK
   $mailersend = new MailerSend(['api_key' => 'your MailerSend token']);

   // send the email
   $mailersend->bulkEmail->send($emails);

   // update the guests that have been reminded
   DB::table('guests')
       ->whereIn('id', $sentToGuestIds)
       ->update(['reminded' => 1]);
}

Since bulk emails are delivered in batches to avoid overloading mailbox providers, you need to check and send reminders every minute. To do this, create a method called checkReminders on a class called EventReminder, calling it from an index file or another entry point. Then start this automation using a cron job:

* * * * * php /home/user/check_reminders/reminders.php

To help you get started with scheduled email delivery, you can download all the sample code and files here.

Or schedule batch emails with the send_at parameter

Alternatively, instead of creating your own routine, you can schedule any email sending by adding the send_at parameter to your Email request, whether it’s a batch or single sending.

Add the scheduling parameter while setting up your email by adding: 

   ->setSendAt(1665626400);

In the example above, it would give:

$email = (new EmailParams())
     ->setFrom('your from email address')
     ->setFromName('your from name')
     ->setRecipients($recipients)
     ->setSubject('Only {$daysleft} {$dayslabel} left for {$event_name}!')
     ->setTemplateId('your template id')
     ->setVariables($variables);
     ->setSendAt(1665626400);

Make sure the send_at parameter has a Unix timestamp set in the future for up to a maximum of 3 days from when the call is made.

Enable the “Precedence: Bulk” header for batch emails

The “Precedence: Bulk” header is a hidden header in your email that lets Gmail know that your email was sent to multiple recipients.

This simply informs Gmail that your bulk email was intentional, preventing your email from going to spam and your inbox from being overwhelmed with auto-responders, such as out-of-office notifications.

To enable the “Precedence: Bulk” header in MailerSend:

1. Go to Domains and click Manage next to the domain you want to enable the header for.
2. In the Advanced settings section, click More settings and toggle Add precedence bulk header on.

Schedule your email sendings now

MailerSend’s bulk email endpoint lets you delay batch email delivery. With more sending options to choose from, you can use triggered emails and scheduled email delivery to match your use case!

Improve your batch email sending today!

Join MailerSend for free and get 12,000 emails/month.

Triggered or scheduled emails. Which ones do you use most often and why? Share in the comments below.

Agathe
I'm Agathe, Product Manager at MailerSend. When I'm not busy rolling out new product features, I'm planning my future mud-brick farmhouse complete with farm animals and a vineyard!
Stop War! Help Ukraine! See what you can do