Bref is a composer package that makes it easy to run serverless PHP applications on AWS Lambda. It achieves this by providing the required layers needed to run PHP applications since they are not supported natively on Lambda.
In this tutorial, we will be building and deploying a serverless PHP application that processes incoming emails programmatically using SendGrid Inbound Parse.
To follow along, you will need:
To get started, create a folder for your application (I am naming mine bref-email-watch
) and enter into the directory with the command below:
$ mkdir bref-email-watch && cd bref-email-watch
Install the application dependencies which comprise the bref CLI, phpdotenv
to enable us to load environment variables from a .env
file, and nexylan/slack
to interact with Slack’s API:
$ composer require bref/bref vlucas/phpdotenv nexylan/slack php-http/discovery
With our dependencies installed, initialize Bref by running ./vendor/bin/bref
in the project directory and select the HTTP option from the interactive menu.
Output of “bref init” command
The command will create a serverless.yml
file which acts as the manifest for how the serverless framework will deploy your application as well as an index.php
file to serve as an entry point into the application.
Next, create a .env
file in the project folder and add the Slack hook URL:
SLACK_HOOK_URL="HERE_LIVES_YOUR_SLACK_HOOK_URL"
The application works by receiving JSON payloads (in the form of HTTP post
requests) from SendGrid each time there is a new mail on the configured domain. We will modify the generated index.php file to parse these payloads, extract the sender and the recipient (using regex and PHP’s preg_match()
), and send a Slack message to the relevant channel containing the extracted data.
Open the index.php
file and replace its content with the code block below:
try {
if (strtoupper($_SERVER['REQUEST_METHOD'] != 'POST')) {
throw new Exception("Received non-post request on webhook handler");
}
if (json_last_error() != JSON_ERROR_NONE) {
$em = "Error while parsing payload: ".json_last_error_msg();
throw new Exception($em);
}
$from = $_POST['from'];
$to = $_POST['to'];
preg_match("#<(.*?)>#", $from, $sender);
preg_match("#<(.*?)>#", $to, $recipient);
$senderAddr = $sender[1];
$recipientAddr = $recipient[1];
$message = "*You've got mail!*\n";
$message .= "*To:* ".$recipientAddr."\n";
$message .= "*From:* ".$senderAddr;
notifyOnSlack($message, true);
// send OK back to SendGrid so they stop bothering our webhook
header("Content-type: application/json; charset=utf-8");
echo json_encode(["message" => "OK"]);
exit(0);
} catch (Exception $e) {
notifyOnSlack($e->getMessage());
header("Content-type: application/json; charset=utf-8");
http_response_code(400);
echo json_encode(["message" => $e->getMessage()]);
exit(0);
}
In the previous code block, we referenced a notifyOnSlack
function that doesn’t exist yet. This function is responsible for sending the $message
parameter it receives to Slack. To implement it, load the variables declared in the .env
file into your application by adding the following code to the top of the index.php
file (just before the try block):
require_once './vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
Next, wire up the function implementation, like this:
function notifyOnSlack($message, $markdown = false)
{
$slackHookUrl = $_ENV["SLACK_HOOK_URL"];
$options = [
"channel" => "#general",
"allow_markdown" => $markdown,
"username" => "bref-email-watch",
];
$client = new Nexy\Slack\Client(
\Http\Discovery\Psr18ClientDiscovery::find(),
\Http\Discovery\Psr17FactoryDiscovery::findRequestFactory(),
\Http\Discovery\Psr17FactoryDiscovery::findStreamFactory(),
$slackHookUrl,
$options
);
$client->send($message);
}
The function loads the SLACK_HOOK_URL
environment variable from the .env file and then sets up the options, which includes the channel the message is to be sent to, to then be passed to the Slack client. We also instantiate the client by passing in the HTTPlug discovery services which allow it to find and use any HTTP client that conforms to the PSR standard.
Now that our application is set up, start the built-in PHP server on port 3000 and open an ngrok
tunnel on the same port:
$ php -S localhost:3000
$ ngrok http 3000
The ngrok
command generates Forwarding URL, like this_:_
Copy the URL and visit your SendGrid’s Inbound Parse settings page. Now, click on the Add Host & URL button and paste in the copied URL in the Destination URL field.
You may want to set up a proper subdomain since SendGrid will notify your webhook of EVERY email that comes to the domain name (irrespective of the username).
Next, send an email to an email address on the domain you specified and the notification should show up on Slack like this:
sample slack notification
#php #sendgrid #serverless #developer