Low-Stock Alert Emails
The feature that makes this app useful: when a product’s quantity drops to its minStockLevel, the store owner automatically gets an email — no one has to remember to check.
When to Check
There are two complementary ways to catch low stock. Start with the first; add the second later if you like.
Decide who receives alerts. Add STORE_OWNER_EMAIL="owner@store.com" to server/.env. This is the exact key the email service reads — if it's not set, it falls back to EMAIL_USER. Do not use ALERT_EMAIL, that key does not exist in this project.
The checkLowStock Function
A tiny function that compares the numbers and emails when needed. It reuses the same sendMail from the Authentication page.
import { sendLowStockAlert } from './services/emailService.js'
// sendLowStockAlert is called from productController.js after every create/update:
const triggerLowStockAlert = (product) => {
if (product.quantity <= product.minStockLevel) {
sendLowStockAlert(product).catch((err) =>
console.error('Failed to send low-stock alert:', err.message)
)
}
}
// Inside sendLowStockAlert (services/emailService.js):
// → sends to process.env.STORE_OWNER_EMAIL or EMAIL_USER as fallback
// → subject: '⚠️ Low Stock Alert: <product.name>' or 'U0001f6a8 Out of Stock: <product.name>'
// → shows product name, SKU, category, current quantity, and minStockLevelAs written, every update at-or-below the threshold sends an email. To send once per dip, add a lowStockNotified boolean to Product: set it true when you alert, and reset to false when a restock pushes quantity back above minStockLevel. Only email when it’s currently false.
A Scheduled Daily Sweep
Optional enhancement — not in the base reference app. A backstop that emails a digest of everything currently low, running on a timer independent of user actions.
import cron from 'node-cron'
import Product from '../models/Product.js'
import { sendLowStockAlert } from '../services/emailService.js'
// every day at 09:00 — a safety-net sweep
cron.schedule('0 9 * * *', async () => {
const lowStock = await Product.find({
$expr: { $lte: ['$quantity', '$minStockLevel'] },
})
for (const product of lowStock) {
sendLowStockAlert(product).catch(console.error)
}
})
// npm install node-cron
// Import this file once in server.js after connectDB()"0 9 * * *" = minute 0, hour 9, every day. Use crontab.guru to build your own schedule.
Test the Alert
Make a product go low and confirm the email lands in your Mailtrap inbox.
- Create a product with
quantity: 5,minStockLevel: 5→ an alert should send immediately (5 ≤ 5). - Or update an existing product’s
quantitydown to itsminStockLeveland watch the inbox. - Open Mailtrapand read the “⚠️ Low stock” email.
- ✓
STORE_OWNER_EMAILset inserver/.env - ✓
triggerLowStockAlert()called in create + update handlers - ✓Email arrives when
quantity ≤ minStockLevel - ✓No email when stock is healthy