Send Inspirational Quotes Every Morning in PHP Using Cron, SendGrid, Twilio SMS and Quote APIs

August 16, 2019
Written by
Michael Jaroya
Contributor
Opinions expressed by Twilio contributors are their own

Create A Daily Inspirational App in PHP.png

Ever had one of those mornings when you woke up unmotivated, but read a quote and the energy returned? That is the power of positive and motivational quotes.

Motivational quotes have a way of making people feel inspired and energized. This phenomenon can be attributed to a combination of factors such as motivational psychology, wordsmithing, and self-selection.

In this tutorial, I am going to teach you how to create an app that automatically sends you motivational quotes every morning. Before we start, here is a motivational quote to uplift you as you follow along.

Believe in yourself! Have faith in your abilities! Without humble but reasonable confidence in your own powers, you cannot be successful or happy. – Norman Vincent Peale

Getting Started

To complete this tutorial, you will need the following:

Create a New Laravel Project

Let’s create a new Laravel project by running the following command:

$ composer create-project laravel/laravel quote-app
$ cd quote-app

Set up the Twilio SDK and SendGrid Mail Driver

First, we need to install the Twilio PHP SDK using Composer. In your terminal, run the command below:

 

$ composer require twilio/sdk

Next, we need to set up our Laravel application to use SendGrid as the mail driver. Here is a link to a quick guide on how to set up SendGrid as your SMTP relay in Laravel. 

After you have completed the setup of your SMTP relay, we will install Guzzle to execute the HTTP API requests. If you are unfamiliar, Guzzle is a great alternative to writing your server-side requests in cURL. Run the command below to install the latest version:

$ composer require guzzlehttp/guzzle

Once these steps are complete, update the .env file with the credentials from your Twilio and SendGrid dashboards as shown below:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=25
MAIL_USERNAME=apikey
MAIL_PASSWORD="Your password"
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="Your email"
MAIL_FROM_NAME="Michael Jaroya"
TWILIO_SID="Your Twilio SID"
TWILIO_AUTH_TOKEN="Your Twilio Auth Token"
TWILIO_PHONE_NUMBER="Your Twilio SMS enable phone number"

Create the Quote App

Let's flesh out the Quote model. Under normal circumstances, our model would primarily be responsible for reading and writing data into the table. We will extend its functionality with custom methods to fetch quotes from the forismatic and favqs APIs and send quotes. Finally, we will create the Quote artisan command to exploit our methods and provide CLI access to them.

Let's jump right in and get motivated :)

Create the Quote Model

Run the command below to create the model:

$ php artisan make:model Quote

Create the Logic to Fetch and Send the Quotes

Because our goal is to generate diverse, random quotes, we will use a single function to fetch a quote from both the forismatic and favqs APIs. Open the app/Quote.php file and add the following method.

<?php
   use GuzzleHttp\Client as GuzClient;
   /**
    * Fetch quotes from the Forismatic and Favqs APIs
    */
   public function fetchQuotes() : Array {

       $client = new GuzClient();
       $quotes=[];

       // Get quote from forismatic
       $request  =  $client->get('http://api.forismatic.com/api/1.0/?method=getQuote&format=json&lang=en');
       $data     = json_decode($request->getBody()->getContents());
       $quotes[] = $data->quoteText . "-" . $data->quoteAuthor;

       // Get quote from Favqs
       $client   = new GuzClient();
       $request  = $client->get('https://favqs.com/api/qotd');
       $data     = json_decode($request->getBody()->getContents());
       $quotes[] = $data->quote->body . "-" . $data->quote->author;

       return $quotes;
   }

In the code above, a GET request is made to the two APIs. From the responses, the quote and author are extracted. The function then returns an array containing two quotes.

Next, we need to create a function to send the fetched quotes via SMS and email them using Twilio and SendGrid respectively.

Add the code below to the Quote model:

<?php
use Twilio\Rest\Client;
   /**
   * send Twilio SMS
   *
   * @param $to
   * @param $sms_body
   */
   function sendSMS( $to, $sms_body ) {
   // Your Account SID and Auth Token from twilio.com/console
     $sid    = getenv( 'TWILIO_SID' );
     $token  = getenv( 'TWILIO_AUTH_TOKEN' );
     $client = new Client( $sid, $token );
     $client->messages->create(
        $to,
        [
           // A Twilio phone number you purchased at twilio.com/console
           'from' => getenv( 'TWILIO_PHONE_NUMBER' ),
           // the body of the text message you'd like to send
           'body' => $sms_body[0]." ".$sms_body[1]
        ]
     );
   }

The sendSMS() function accepts two parameters; the number of the recipient and the quotes in the form of the SMS body. Those parameters are then used to send an SMS using your Twilio enabled phone number.

Next, let's create the function to send the quotes via email. In app/Quote.php add the following code:

<?php
use App\Mail\EmailQuotes;
use Mail;
    /**
     * Send email using SendGrid
     * @param $email_address
     * @param $body
     */
    public function sendEmail($email_address,$body){
        Mail::to($email_address)->send(new EmailQuote($body));
    }

The  sendEmail() function accepts two parameters; the email address of the recipient and the email body and then sends the email using a Mailable class. We’ll break down what a Mailable class is in the next section.

Creating a Mailable Class

In Laravel, each type of email sent by your application is represented as a "mailable" class. These classes are stored in the app/Mail directory.

In your terminal, run the artisan command below:

$ php artisan make:mail EmailQuote

The command generates a new file app/Mail/EmailQuote.php.

The Mailable class has a build function where we can define the configurations for our email, indicate the template view file to be used, and also pass any needed parameters to our view template.

Update the file as shown below:

<?php
namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class EmailQuote extends Mailable
{
   use Queueable, SerializesModels;

   protected $email_body;

   /**
    * Create a new message instance.
    *
    * @return void
    */
   public function __construct($email_body)
   {
       $this->email_body=$email_body;
   }

   /**
    * Build the message.
    *
    * @return $this
    */
   public function build()
   {
       $data=implode("<br>",$this->email_body);
       return $this->view('emails.quote')->with(['email_body'=>$data]);;
   }
}

Next, create an emails  folder under resources/views and add a file quote.blade.php.

Update the file as shown below:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <h3>Hello,</h3>
        <br>
        <p>Quotes of the day:</p>
        <br>
        <p>{{$email_body}}</p>
    </body>
</html>

Consolidating the App

Our app is now taking shape. Since we have all of the components needed to build the app, let’s put everything together. Reopen the Quote model in app/Quotes.php and add this final method:

   /**
    * The Quote App
    */
   public function quoteApp(){
       // ideally this should come from a database
       $recipients=
       [
           [
           'to' => '07XXXXXXXX',
           'email_address' => 'email@example.com'
           ]
       ];
       $quote=$this->fetchQuotes();
       foreach($recipients as $recipient){
           // send sms
           $this->sendSMS($recipient['to'],$quote);
           // send email
           $this->sendEmail($recipient['email_address'],$quote);
       }
   }

The Quote Artisan Command

Since the app needs to send quotes every day, we need to create a way to automate the process through task scheduling. In Laravel, we can achieve this through a number of ways notably through scheduling artisan commands, Queue jobs, shell commands e.t.c.

I have opted to create a custom artisan command due to its simplicity, but you can opt for any of the options available.

Laravel's command scheduler allows you to fluently and expressively define your command schedule within Laravel itself. When using the scheduler, only a single Cron entry is needed on your server. Your task schedule is defined in the app/Console/Kernel.php file's schedule method.

Run the artisan command below to generate the artisan command:

$ php artisan make:command sendQuotes

This command created a new command class in the app/Console/Commands directory.

Open the file app/Console/Commands/sendQuote.php and update the signature variable and the handle method as shown below:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Quote;

class sendQuotes extends Command
{
   /**
    * The name and signature of the console command.
    *
    * @var string
    */
   protected $signature = 'send:quote';

   /**
    * The console command description.
    *
    * @var string
    */
   protected $description = 'send SMS and Email using Twilio and SendGrid respectively';

   /**
    * Create a new command instance.
    *
    * @return void
    */
   public function __construct()
   {
       parent::__construct();
   }

   /**
    * Execute the console command.
    *
    * @return mixed
    */
   public function handle()
   {
       $quote=new Quote();
       $quote->quoteApp();
       $this->info('Success :)');
   }

Next, update app/Console/Kernel.php file's schedule method with this single line of code.

   protected function schedule(Schedule $schedule)
   {
       $schedule->command('send:quote')->dailyAt('6:00');
   }

This command simply means, call php artisan send:quote (the command we have just created) daily at 6.00 am in the morning.

Finally, add the following Cron entry to your server.

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

This Cron will call the Laravel command scheduler every minute. When the schedule:run command is executed, Laravel will evaluate your scheduled tasks and runs the tasks that are due.

Testing

To test the final app, navigate to your project directory and run the artisan command below:

$ php artisan send:quote

If all went well, you should get both an SMS and an email.

SMS screenshot

 

Email screenshot

Conclusion

The aim of this tutorial is to keep things as simple as possible. To build upon this app, you can create an online portal where users can subscribe to get the quote of the day by providing either a phone number or email. The code is available on Github.

Have some ideas to better improve the app? Let me know. I can’t wait to see what you build.

Feel free to reach out to me: