Skip to content

Instantly share code, notes, and snippets.

@princefishthrower
Created February 27, 2024 09:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save princefishthrower/4517ff44a9f4c5b2d205343feabe08b8 to your computer and use it in GitHub Desktop.
Save princefishthrower/4517ff44a9f4c5b2d205343feabe08b8 to your computer and use it in GitHub Desktop.
Netlify serverless function that sends a warning email / SMS if the bandwidth is close to the specified limits.
// This Netlify serverless function will send a warning email / SMS if the bandwidth is close to the specified limits.
// Many environment variables need to be set in order for this function to work:
// - MJ_API_KEY (Mailjet API key)
// - MJ_API_SECRET (Mailjet API secret)
// - SINCH_SERVICE_PLAN_ID (Sinch service plan ID)
// - SINCH_API_TOKEN (Sinch API token)
// - SINCH_NUMBER (Sinch phone number)
// - SINCH_TO_NUMBER (Sinch phone number to send the SMS to)
// - NETLIFY_ACCESS_TOKEN (Netlify access token) - generate one at https://app.netlify.com/sites/{your-site-name}/settings/general#access-control
// - NETLIFY_API_BANDWIDTH_URL (Netlify API bandwidth URL) - should have this pattern: https://api.netlify.com/access-control/bb-api/api/v1/accounts{your-account-id}/bandwidth
// It's recommended to set this up as an hourly scheduled function in your netlify.toml file:
// # ./netlify.toml
// # Hourly warn bandwidth function
// [functions."warn-bandwidth"]
// schedule = "@hourly"
import { Handler } from '@netlify/functions'
import Mailjet from 'node-mailjet'
// Note: Warning thresholds must be defined in ascending order!
const warningThresholds = [25, 50, 75, 99]
// The threshold for sending an SMS (greater than or equal to)
const smsThreshold = 75
const sendWarningEmail = async (threshold: number, percentage: number, periodEndDate: string) => {
const mailjet = Mailjet.apiConnect(process.env.MJ_APIKEY_PUBLIC || '', process.env.MJ_APIKEY_PRIVATE || '')
try {
await mailjet.post('send', { version: 'v3.1' }).request({
Messages: [
{
From: {
Email: 'yourtoemail@email.com',
Name: 'From Name'
},
To: [
{
Email: 'yourtoemail@email.com',
Name: 'To Name'
}
],
Subject: `WARNING: Your Netlify bandwidth has exceeded ${threshold}%!`,
TextPart: `WARNING: Your Netlify bandwidth usage has exceeded ${threshold} and is currently at ${percentage}%! Your bandwidth allocation renews on ${periodEndDate}.`,
HTMLPart: `WARNING: Your Netlify bandwidth usage has exceeded ${threshold} and is currently at ${percentage}%! Your bandwidth allocation renews on ${periodEndDate}.`
}
]
})
console.log(`Warning email successfully sent for exceeding ${threshold}% threshold.`)
} catch (err: any) {
console.log('Error sending warning email', err.statusCode)
}
}
const sendSMS = async (threshold: number, percentage: number, periodEndDate: string) => {
try {
const resp = await fetch('https://us.sms.api.sinch.com/xms/v1/' + process.env.SINCH_SERVICE_PLAN_ID + '/batches', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + process.env.SINCH_API_TOKEN
},
body: JSON.stringify({
from: process.env.SINCH_NUMBER,
to: [process.env.SINCH_TO_NUMBER],
body: `WARNING: Your Netlify bandwidth usage has exceeded ${threshold} and is currently at ${percentage}%! Your bandwidth allocation renews on ${periodEndDate}.`
})
})
const data = await resp.json()
console.log(data)
} catch (err: any) {
console.log('Error sending SMS', err)
}
}
const warnIfBandwidthExceeded = async () => {
const netlifyAuth = `Bearer ${process.env.NETLIFY_ACCESS_TOKEN}`
const bandwidthUrl = `${process.env.NETLIFY_API_BANDWIDTH_URL}`
const response = await fetch(bandwidthUrl, {
method: 'GET',
headers: {
'User-Agent': 'YourApp (youremail@email.com)',
Authorization: netlifyAuth
}
})
const data = await response.json()
if (data.used && data.included && data.period_end_date) {
const used = data.used
const included = data.included
const percentage = Math.round((used / included) * 100)
const periodEndDate = new Date(data.period_end_date).toLocaleDateString()
for (const threshold of warningThresholds) {
if (percentage > threshold) {
sendWarningEmail(threshold, percentage, periodEndDate)
if (smsThreshold >= 75) {
sendSMS(threshold, percentage, periodEndDate)
}
return
}
}
}
}
const handler: Handler = async () => {
try {
await warnIfBandwidthExceeded()
return {
statusCode: 200,
body: 'OK'
}
} catch (error) {
console.log(error)
return {
statusCode: 500,
body: 'Unknown error'
}
}
}
export { handler }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment