Your app knows things worth telling people about. An order shipped. A server went down. A job got assigned. The two workhorse channels for getting that news out are SMS and email, and the two workhorse services are Twilio and SendGrid. In this guide you'll set up both in a Node app: buy a Twilio number and send a text, then send email through SendGrid, with API keys handled properly. By the end you'll have working alert functions you can call from anywhere in your code.
Prerequisites
- Node.js 18 or newer.
- A Twilio account (free trial works for testing, with limitations noted below).
- A SendGrid account (the free tier is enough to start).
- A domain you control, if you want email that actually lands in inboxes.
Step 1: Buy a Twilio phone number
In the Twilio Console, go to Phone Numbers, then Buy a Number. Filter for SMS capability, pick a local number, and buy it. A standard US local number costs a dollar or so per month, and outbound texts cost a fraction of a cent each.
While you're in the Console, grab your Account SID and Auth Token from the account dashboard. Those two values plus the phone number are everything the code needs.
One trial-account gotcha: until you upgrade to a paid account, Twilio only lets you text phone numbers you have verified, and it prepends a trial notice to every message. Fine for testing, useless for production.
Step 2: Put credentials in environment variables
Never hardcode API credentials, and never commit them. Locally, use a .env file (and add it to .gitignore):
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_FROM_NUMBER=+15551234567
SENDGRID_API_KEY=SG.xxxxxxxxxxxx
ALERT_FROM_EMAIL=alerts@yourdomain.com
In production, set the same variables through your host's config (every platform has a place for this). Same code, different values, no secrets in the repo.
Step 3: Send an SMS with the Twilio SDK
Install the SDK:
npm install twilio
Then a minimal send function:
const twilio = require('twilio');
const client = twilio(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
async function sendSms(to, body) {
const message = await client.messages.create({
from: process.env.TWILIO_FROM_NUMBER,
to,
body,
});
console.log('SMS queued, SID:', message.sid);
return message.sid;
}
// Example:
// sendSms('+15559876543', 'Server db-01 is not responding.');
Phone numbers go in E.164 format: plus sign, country code, number, no dashes or spaces. The returned SID is your receipt; you can look it up in the Console's message logs if a text goes missing.
Step 4: A2P registration for US texting
This is the part nobody tells you until your messages stop delivering. US carriers require businesses sending application-to-person (A2P) SMS to register their brand and messaging use case through Twilio's A2P 10DLC process. Unregistered traffic gets filtered or blocked, and it has gotten stricter every year.
The registration happens in the Twilio Console: you submit your business information and describe what you'll be sending, and approval takes anywhere from days to a few weeks. There are small registration and monthly fees. If you are only sending alerts to yourself or your own staff, you still need it for reliable delivery to US numbers. Budget the time before launch, not after your alerts silently stop arriving.
Step 5: Get a SendGrid API key and verify a sender
In the SendGrid dashboard, go to Settings, then API Keys, and create a key with Mail Send permission. Copy it immediately; SendGrid shows it once.
Before SendGrid will send anything, you have to prove you own the from address. Two options under Settings, then Sender Authentication:
- Single Sender Verification: verify one email address by clicking a confirmation link. Fast, fine for testing.
- Domain Authentication: add a few DNS records (CNAMEs) to your domain so SendGrid can sign your mail with SPF and DKIM. This is what you want for production. Mail from an authenticated domain lands in inboxes; mail without it increasingly lands in spam or gets rejected outright, especially by Gmail and Yahoo, which now require proper authentication for senders of any real volume.
Step 6: Send email with the SendGrid SDK
npm install @sendgrid/mail
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
async function sendEmail(to, subject, text) {
const [response] = await sgMail.send({
to,
from: process.env.ALERT_FROM_EMAIL,
subject,
text,
});
console.log('Email accepted, status:', response.statusCode);
}
// Example:
// sendEmail('mason@example.com', 'Backup failed',
// 'Nightly backup on db-01 exited with an error at 2:14 AM.');
A 202 status means SendGrid accepted the message, not that it reached the inbox. For alerts you actually depend on, check the Activity feed in the SendGrid dashboard while testing, and consider enabling event webhooks later so bounces get logged somewhere you'll see.
Step 7: Verify it
Wire both functions into a quick test script and run it:
require('dotenv').config();
(async () => {
await sendSms('+1555YOURCELL', 'Test alert from the app.');
await sendEmail('you@yourdomain.com', 'Test alert', 'If you can read this, email works.');
})();
Check that the text arrives, the email arrives in the inbox (not spam), and both dashboards show the messages as delivered. If the email hit spam, finish domain authentication before going further.
Wrap-up and a few deliverability habits
You now have sendSms and sendEmail functions you can call from webhooks, cron jobs, or error handlers. A few habits that keep alerts trustworthy: send from a consistent authenticated domain, keep SMS messages short and identify who they're from, don't blast the same alert every minute (batch or throttle repeats), and log every send with its SID or status code so "did the alert go out" is a lookup, not a mystery.
Stuck on this, or want it done for you? That's the job.
Email us →