How to send bulk SMS in Laravel using XML APIs and Queue

Merwin Poulose

A simple and easy method to send bulk SMS in Laravel with XML APIs using Queue, this will be useful if you want to send more SMS per seconds to your customer or users.

Nowadays every business requires a mode of communication with their customers, whether its retail or service oriented, we might need to send bulk SMS or emails for various bills, transactions, subscriptions or even promotional messages to users. Sending bulk SMS has become easy with XML APIs and many SMS service providers provide XML APIs for sending SMS.


So you have 1000's of users to be notified via SMS regarding your promotions, sales or blah blah blah...What if you run a loop for each mobile number to be notified and sending request to the service provider each time for mobile numbers. Is this the best way to do it?. How much time and resources will be wasted from your side as well as service providers. Why can't we send bulk SMS with a single request, is this possible ?

Yes, with XML APIs we can combine mobile numbers and even customised messages and send in one shot. We will be working on a simple tutorial to send bulk SMS using queues by sending birthday wishes to our users.


Steps to send bulk sms in Laravel using XML APIs

  1. Create Laravel Artisan Command
  2. Create a Job to process SMS
  3. Attach the Artisan command to Kernel for scheduling the Job
  4. Use Supervisor to handle the queue to speed up the SMS sending process

In this tutorial we will be going through a simple process to send bulk SMS to all our users on their birthday, so that birthday wishes are sent from our server without much delay, it also depends upon the network providers for the message delivery. We will be using Laravel Queues and Jobs to speed up the process in background. You can customise and even do more experiments with the same XML APIs like sending customised SMS to your users or customers with certain business logic and even track and analyse SMS delivery.

Create Laravel Artisan Command

php artisan make:command BirthdaySMS

Inside BirthdaySMS.php

public function birthdayUsers()
{
    $users = User::whereMonth('dob', '=', date('m'))
                    ->whereDay('dob', '=', date('d'))
                    ->select('name','mobile')->get();
    $authKey = "xxxxxxxxxxxxxxxxxxx";
    $route = 'x';
    $xmlSMS = array();
    foreach ($users as $sendsms) {
        $message = urlencode('Hi ' . $sendsms->name . ', Vann Studios wish you a very Happy Birthday!');
        $xmlSMS[]["mainContent"] = '<SMS TEXT="' . $message . '"><ADDRESS TO="' . $sendsms->mobile . '"></ADDRESS></SMS>';
    }
    $xmlSMS = collect($xmlSMS);
    $xmlData = '<MESSAGE><AUTHKEY>' . $authKey . '</AUTHKEY><SENDER>MERWIN</SENDER><ROUTE>' . $route . '</ROUTE><CAMPAIGN>Birthday</CAMPAIGN>';
    foreach ($xmlSMS as $sms) {
        $xmlData .= $sms['mainContent'];
    }
    $xmlData .= '</MESSAGE>';
    SendSms::dispatch($xmlData)->onQueue('sms');
}


Create a Job to process the SMS

php artisan make:job SendXMLSMS

Inside SendXMLSMS.php

use Log;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class SendXMLSMS implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    protected $xmlData;

    public function __construct($xmlData)
    {
        $this->xmlData = $xmlData;
    }

    public function handle()
    {
        try{
            $client = new Client(); //GuzzleHttp\Client
            $result = $client->post('your service provider api', [
                'form_params' => [
                    'data' => $this->xmlData
                ]
            ]);
            if($result){
                $result_status = $result->getStatusCode();
                $result_contents = $result->getBody()->getContents();
                //The response from the providers might be different from this.
                //Customise according to the response.
                if(!isset($result_contents))
                    $result_contents = "No Response from operator";
            }else{
                $result_contents = "No Response from operator";
            }
            $contents = str_contains($result_contents, 'code:');
            if($result_status == 200 && ($contents == FALSE))
            { 
                // SMS send successfully. You can update any related tables, when queue finished and much more here 
            }elseif($result_status == 200 && ($contents == TRUE)){
                // Error
                // SMS sending failed. You can update any related tables, when queue finished and much more here 
            }else{
                // Couldn't connect with operator
                // SMS sending failed. You can update any related tables, when queue finished and much more here
            }
            //DB::beginTransaction();
            try {
                //any business logic
                //DB::commit();// all good
            }catch (Exception $e) {
                //DB::rollback();// something went wrong
                $this->failed($e,$result_contents);
            }
        }catch(Exception $e){
            $this->failed($e,$result_contents);
        }
    }

    public function failed(Exception $exception, $result_contents)
    {
        Log::error($result_contents);
        Log::error($exception->getMessage());
        //DB::beginTransaction();
        try {
            //any business logic
            //DB::commit();// all good
        } catch (Exception $e) {
            //DB::rollback();// something went wrong
        }
    }
}


Attach the Artisan command to Kernel for scheduling the Job


  protected function schedule(Schedule $schedule) {
      $schedule->command('sms:birthday')->dailyAt('08:00');
  }


Use Supervisor to handle the queue to speed up the SMS sending process


Supervisor is a process control system. Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems and will automatically restart your queue:work process if it fails. If you need to know how to set up Supervisor and Laravel check the link below

Laravel queues and Beanstalkd

numprocs=20

For this example we will keep the numprocs directive will instruct Supervisor to run 20 queue:work processes and monitor all of them. 

I hope this will help you. Good luck. Cheers!





Back to Tutorials