SMS Notifications with Twilio
Send/receive SMS, verification codes, and webhook handling
What You’ll Build
After following this guide, you will have a working implementation of sms notifications with twilio in your project. Send SMS messages and verification codes using Twilio. Covers sending one-time passwords (OTP) for two-factor auth, transactional SMS notifications, receiving incoming SMS via webhooks, and handling delivery status callbacks.
Use Cases & Problems Solved
- Send transactional emails reliably without landing in spam folders
- Set up notification systems that scale with your user base
- Avoid building email delivery infrastructure from scratch
Prerequisites
- Twilio account with a phone number
- Node.js 18+
Step-by-Step Implementation
Install Twilio SDK
The following snippet shows how to install twilio sdk. Copy this into your project and adjust the values for your environment.
npm install twilio
Send SMS and verification codes
The following snippet shows how to send sms and verification codes. Copy this into your project and adjust the values for your environment.
const twilio = require('twilio')(process.env.TWILIO_SID, process.env.TWILIO_AUTH_TOKEN);
// Send a simple SMS
await twilio.messages.create({
body: 'Your order #1234 has shipped!',
from: process.env.TWILIO_PHONE_NUMBER,
to: '+1234567890',
});
// Send OTP verification code
app.post('/auth/send-otp', async (req, res) => {
const code = Math.floor(100000 + Math.random() * 900000).toString();
await redis.setex(\`otp:\${req.body.phone}\`, 300, code); // 5 min expiry
await twilio.messages.create({
body: \`Your verification code is: \${code}. Expires in 5 minutes.\`,
from: process.env.TWILIO_PHONE_NUMBER,
to: req.body.phone,
});
res.json({ sent: true });
});
// Verify the OTP
app.post('/auth/verify-otp', async (req, res) => {
const stored = await redis.get(\`otp:\${req.body.phone}\`);
if (stored !== req.body.code) return res.status(401).json({ error: 'Invalid code' });
await redis.del(\`otp:\${req.body.phone}\`);
res.json({ verified: true });
});
⚠️ Don’t Do This
❌ Using predictable OTP codes or no expiration
// Sequential codes are guessable! No expiration = unlimited attempts
let counter = 0;
const code = (++counter).toString().padStart(6, '0');
✅ Use cryptographically random codes with short expiration
const crypto = require('crypto');
const code = crypto.randomInt(100000, 999999).toString();
await redis.setex(`otp:${phone}`, 300, code); // 5 min, then deleted
Testing
Verify your implementation with these tests:
// __tests__/sms-notifications-with-twilio.test.ts
import { describe, it, expect } from 'vitest';
describe('SMS Notifications with Twilio', () => {
it('should initialize without errors', () => {
// Test that the setup completes successfully
expect(() => setup()).not.toThrow();
});
it('should handle the primary use case', async () => {
const result = await execute();
expect(result).toBeDefined();
expect(result.success).toBe(true);
});
it('should handle edge cases', async () => {
// Test with empty/null input
const result = await execute(null);
expect(result.error).toBeDefined();
});
});
Verification
# Send a test SMS:
node send-sms.js +1234567890
# Check your phone for the message
# Test OTP flow: send code, then verify with correct/incorrect codes Related Specs
Send Emails with Resend
React Email templates, attachments, batch sending, and delivery tracking
Email Templates with React Email
Responsive templates, components, preview server, and testing