This content originally appeared on Twilio Blog and was authored by Dhruv Patel
Introduction
Sitting at your device all day waiting for a price drop on a product can be a cumbersome task. An email notification system will ensure that you never miss out on your most coveted item. Whether you’re looking for the hottest pair of shoes or a couch for your living room, it can all be automated to your benefit and make technology work for you.
In this article, you will learn how to build an email price notification system. To do this, you’ll use the Sneaks API to track sneaker prices and deliver SendGrid email alerts whenever the price of a particular sneaker decreases.
Prerequisites
Here is what you will need to follow along with this article:
- Node.js installation
- A free SendGrid account
- An email address to test out this project
Configure Your Environment
In this section, you will first configure your environment by setting up your SendGrid account, and building the scaffolding for your email notification system.
Generate your SendGrid API key
Start off by logging into your SendGrid account and heading to the API Keys section. Click the blue “Create API Key” button on the top right.
Choose whatever name you’d like for your API key and click the blue “Create & View” button. Copy your API key and store it in a safe place.
Create your project structure
The next step is to build the scaffolding for your Node.js project in your preferred directory. Inside your terminal or command prompt, navigate to your preferred directory and enter:
mkdir email-notifier
cd email-notifier
The next step is to initiate a brand new Node.js project and to install the dependencies required for this project:
npm init -y
npm install @sendgrid/mail dotenv sneaks-api fs node-schedule
You will need the @sendgrid/mail
package which allows you to use the Twilio SendGrid API to send and receive emails. dotenv
is used to access environment variables, which is where you will store your SendGrid API key needed to interact with the API. The sneaks-api
package is used to track sneaker prices. The fs
package will allow us to interact with our subscribers database which we will simulate using a JSON file. Lastly, the node-schedule
package is used to schedule the price checker.
In a production app, it's recommended to use an actual database to store your subscribers. Storing data in files is prone to issues such as file corruption, size limitations, locks, etc. If you’d like to use an actual database to store your subscribers for your project, check out this tutorial.
Once your Node.js app is initialized with the dependencies, your next step is open your preferred text editor and create three new files inside your email-notifier directory: index.js, .env, and subscribers.json.
The index.js file will continuously run and will check and notify subscribers if their sneaker has dropped below a certain threshold. The .env file will securely store all of your environmental variables. The subscribers.json will hold all of your subscribers along with their data.
Your SendGrid API key you created earlier can be securely stored in the .env file. Open up the .env file and copy and paste the following into it:
SENDGRID_API_KEY=XXXXXXX
Once copied in the .env file, replace the XXXXXXX
placeholders with your actual API key.
Simulate subscribers and build a scheduler
Because you’re building a price notifier that alerts subscribers to a price change of a given product, you’ll need some subscribers to send the alerts to. Normally, in a production app, you would use a database to store your subscribers but in this case you’ll create some fake subscribers and store them as objects in a JSON file. Copy and paste the following code into the subscribers.json file:
[
{
"email": "you@example.com",
"styleID": "FY2903",
"lastResellPrice": 475
},
{
"email": "you@example.com",
"styleID": "DD0587-600",
"lastResellPrice": 285
}
]
The “email”
key in each of the objects in the Subscribers array stores the email address of the subscriber. Make sure you enter your own email address here. The “styleID”
key stores the style ID of the sneaker being tracked and the “lastResellPrice”
key stores the last tracked price of the sneaker.
Your email notification system needs to send out alerts whenever the price drops for a subscriber’s tracked sneaker. The index.js file you created earlier will go through the subscribers collection and check whether the price of their tracked sneaker has dropped below a certain threshold. If the price has dropped, it will send out an email alert to the user.
At the top of the index.js file insert the following code:
require('dotenv').config()
const SneaksAPI = require('sneaks-api');
const fs = require("fs");
const sneaks = new SneaksAPI();
const schedule = require('node-schedule');
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const jsonString = fs.readFileSync("./subscribers.json");
const subscribers = JSON.parse(jsonString);
This code loads the SendGrid API, and uses dotenv
to load the API with your API key stored in the .env file. It also includes the sneaks-api
package, the fs
module and the subscribers.json file. Ensure to replace the email addresses in the subscribers file with your own email address so you’re able to test out and see price alerts.
This next section is the main function that loops through all the subscribers, grabs their current shoe price and sends out an email alert if the price has dropped; add this to the index.js file. You’ll notice references to helper functions, which you will add in the next section.
(async function main() {
const sneakerMap = await getSneakerMap(subscribers);
for await (const subscriber of subscribers) {
if (sneakerMap[subscriber.styleID].price < subscriber.lastResellPrice - 10) {
notifySubscriber(sneakerMap[subscriber.styleID], subscriber.email);
subscriber.lastResellPrice = sneakerMap[subscriber.styleID].price;
}
}
fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers));
})()
The getSneakerMap()
function outputs a map of all sneaker style IDs in the subscribers collection along with their current price. Once this map is generated, the code loops through all the subscribers and checks their current shoe in the map to see if their shoe price has dropped.
If it has dropped by $10, it will then run the notifySubscriber()
function which sends out an alert to the user and will update the last resell price of the subscribers shoe from the sneaker map and then move on to the next subscriber. Once this loop ends, the subscribers.json file will be updated with the new prices.
Helper functions
Right below your main function is where you’ll place your helper functions. These helper functions will help your code be a bit more modular and will make your code easier to read.
The getSneakerMap()
function takes in the list of subscribers, iterates through them and uses the sneaksApiFunctionWrapper()
to grab all the sneaker objects from the sneaks-api. These objects will be placed in a map where its key values are its style ID. Add this function before the main()
function in index.js.
async function getSneakerMap(subscribers) {
var sneakerMap = new Object();
for (const subscriber of subscribers) {
if (sneakerMap[subscriber.styleID]) continue;
const sneaker = await sneaksApiFunctionWrapper(subscriber.styleID);
sneakerMap[subscriber.styleID] = sneaker;
}
return sneakerMap;
}
The notifySubscriber()
function is the core of the scheduler - it will run if a subscriber needs to be notified and takes in a sneaker and an email address and sends an email alert to the address using the SendGrid API. This function uses the sgMail
variable we initialized earlier with the SendGrid Node.js helper library. Instead of sending a plain text notification email, the SendGrid API provides you a way to send a stylized email with HTML. Line 6 will send a stylized HTML document to the email generated by createEmailInHTML()
function.
Add notifySubscriber
right after getSneakerMap
in index.js.
function notifySubscriber(sneaker, email) {
const msg = {
to: email,
from: SENDER_EMAIL, // Change to your verified sender
subject: `Price Drop - ${sneaker.name}`,
html: createEmailInHTML(sneaker),
}
sgMail.send(msg);
}
When using SendGrid, it's recommended to verify your Sender Identity by completing Single Sender Verification or Domain Authentication. For a step-by-step tutorial on this check out: How to set up domain authentication for Twilio SendGrid
On line 4, replace the SENDER_EMAIL
placeholder with your email.
The sneaksApiFunctionWrapper()
function utilizes the sneaks-api
package to format and provide the information we need. Add this function after notifySubscriber
in index.js.
function sneaksApiFunctionWrapper(styleID) {
return new Promise((resolve, reject) => {
sneaks.getProductPrices(styleID, function (err, product) {
const lowestResellSite = Object.keys(product.lowestResellPrice).reduce((a, b) => product.lowestResellPrice[a] > product.lowestResellPrice[b] ? a : b);
const sneaker = {
name: product.shoeName,
image: product.thumbnail,
site: lowestResellSite,
price: product.lowestResellPrice[lowestResellSite],
url: product.resellLinks[lowestResellSite],
styleID: product.styleID
};
resolve(sneaker);
}, (errorResponse) => {
reject(errorResponse);
});
});
}
Lastly the createEmailInHTML()
takes in the sneaker and generates a stylized document displaying the price drop for it as well as an image of the sneaker and a button that redirects the user to the product page.
function createEmailInHTML(sneaker) {
return `
<h2>
<img style="font-size:14px;display:block;margin-left:auto;margin-right:auto;width:200px; padding-bottom:15px"
src="https://raw.githubusercontent.com/druv5319/Sneaks-API/master/Screenshots/Sneaks_Logo.png" />
</h2>
<div
style=" margin-left: auto; margin-right: auto;box-sizing:border-box;width:45%; margin-bottom:30px;background:#fdfdfd;border:1px solid #f0f0f0">
<h2 style="text-align: center; color: black; font-family: 'avenir';">Price Drop - ${sneaker.name}</h2>
<p>
<img style="display: block; margin-left: auto; margin-right: auto;" src=${sneaker.image} alt="" width="auto"
height="250" />
</p>
<h2 style="text-align: center; color: black; font-family: 'avenir';">$${sneaker.price}</h2>
<p> </p>
<p style="font-size: 1.5em; color: black; font-family: avenir; text-align: center;">${sneaker.name} has dropped to
<strong>$${sneaker.price}</strong> on <strong>${sneaker.site}</strong></p>
<p style="text-align: center;">
<a href="${sneaker.url}"
style="box-sizing:border-box;border-color:#348eda;font-weight:400;text-decoration:none;display:inline-block;margin:0;color:#ffffff;background-color:#348eda;border:solid 1px #348eda;border-radius:2px;font-size:14px;padding:12px 45px; font-weight: 600;">Buy
now on ${sneaker.site}</a>
</p>
</div>`;
}
Test Your Notifier
Now that your index.js file has been built, it’s time to test it out!
To ensure your code is correct, here is the full code for the index.js file.
Head over to your terminal and navigate to your project directory. Paste in the following command:
node index.js
This command will run the index.js file and will notify the emails in the subscribers.json file if there was a price drop on their sneakers. But before you execute this command, change the existing prices in the subscribers.json file to a higher value and the emails to your own email to ensure your notifier works and that you’ll receive an email.
Now run the command in your terminal and in a few seconds you’ll see an email regarding the price drop in your inbox.
Taadaa! Now it’s time to put your notifier to use!
Create your scheduler
Your main function needs to run automatically on a schedule to send out alerts whenever the price drops for a subscriber’s tracked sneaker - For this, you will use the node-schedule
package to schedule time-based jobs. For a deeper dive on this, check out How to Send Recurring Emails in Node.js with SendGrid.
In your index.js file, replace the main function with the following:
const job = schedule.scheduleJob('*/10 * * * *', function () {
(async function main() {
const sneakerMap = await getSneakerMap(subscribers);
for await (const subscriber of subscribers) {
if (sneakerMap[subscriber.styleID].price < subscriber.lastResellPrice - 10) {
notifySubscriber(sneakerMap[subscriber.styleID], subscriber.email);
subscriber.lastResellPrice = sneakerMap[subscriber.styleID].price;
}
}
fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers));
})()
});
The highlighted lines show that the main function here is wrapped with another function called scheduleJob()
which uses a cron expression as a parameter. The cron expression used is */10 * * * *
and instructs the function to have it run every 10 minutes.
Save the file, run the script again with node index
in the terminal and you’re done! This script will continuously run and will check if a sneaker price has dropped from the subscribers list every 10 minutes.
Summary
Keeping tabs on prices adds another item to your already long to-do list. An email notifier can let you know when your desired price is reached and ready to be in your hands. With Node.js, and SendGrid, you are one step ahead of price volatility. In an ever-changing market, an email notification can be the bridge between you and your most coveted item.
Want to continue building the notifier? Expand your notifier by connecting it to an actual database or utilize SendGrid’s marketing features to use email lists and to provide a way for users to unsubscribe to a sneaker. To have better control of your scheduler, implement a Node.js process manager such as PM2 and Forever which runs your script as a daemon and ensures your application is running 24/7.
Happy Building!
Dhruv Patel is a Developer on Twilio’s Developer Voices team. You can find Dhruv working in a coffee shop with a glass of cold brew or he can either be reached at dhrpatel [at] twilio.com or LinkedIn.
This content originally appeared on Twilio Blog and was authored by Dhruv Patel
Dhruv Patel | Sciencx (2021-12-13T22:21:20+00:00) Send Email Notifications to Subscribers with SendGrid and Node.js. Retrieved from https://www.scien.cx/2021/12/13/send-email-notifications-to-subscribers-with-sendgrid-and-node-js/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.