What are SMS and MMS: Complete Guide for Developers
SMS and MMS are the oldest and most universal mobile messaging technologies in the world. Despite the rise of WhatsApp, Telegram, and other apps, they remain fundamental for user verification, critical notifications, and marketing. In this guide, we explain everything you need to know as a developer.
What is SMS?
SMS stands for
Short Message Service. It's a communication protocol that allows sending text messages between mobile phones through the cellular network.
Main SMS Characteristics
| Maximum length | 160 characters (GSM-7) or 70 characters (Unicode) |
|---|
| Content type | Text only |
|---|
| Requires internet | No |
|---|
| Coverage | 99% of mobile phones |
|---|
| Open rate | ~98% |
|---|
History of SMS
- 1984: First SMS concept proposal
- 1992: First SMS sent ("Merry Christmas")
- 2000s: Consumer usage explosion
- 2010s: Transition to business use (A2P)
- 2020s: Fundamental for 2FA and notifications
How SMS Works Technically
Your application sends the message to an SMS provider (like Zavu)The provider connects to an SMSC (Short Message Service Center)The SMSC locates the recipient's networkThe cell tower delivers the message to the phoneThe phone receives the message without needing internettext
[Your App] --> [Zavu API] --> [SMSC] --> [Cellular Network] --> [Phone]
What is MMS?
MMS stands for
Multimedia Messaging Service. It's an extension of SMS that allows sending multimedia content.
MMS Characteristics
| Maximum size | 300KB - 600KB (varies by carrier) |
|---|
| Content types | Images, videos, audio, vCards |
|---|
| Requires internet | Mobile data |
|---|
| Coverage | ~95% of smartphones |
|---|
| Cost | 3-5x more expensive than SMS |
|---|
MMS Content Types
- Images: JPG, PNG, GIF (up to ~500KB)
- Video: MP4, 3GP (very limited, ~15 seconds)
- Audio: MP3, AAC (short clips)
- vCard: Contact cards
- Long text: Messages without 160 character limit
SMS vs MMS: Key Differences
| Content | Text only | Multimedia + text |
|---|
| Limit | 160 characters | ~600KB |
|---|
| Cost per message | $0.01 - $0.03 | $0.03 - $0.10 |
|---|
| Requires data | No | Yes |
|---|
| Delivery speed | Seconds | Seconds to minutes |
|---|
| Compatibility | Universal | Nearly universal |
|---|
| Main use | 2FA, notifications | Visual marketing |
|---|
When to Use SMS
- User verification (OTP/2FA)
- Critical notifications (security alerts, confirmations)
- Reminders (appointments, payments, renewals)
- Transactional alerts (orders, shipments)
- Markets with limited internet
When to Use MMS
- Visual marketing campaigns
- Promotions with product images
- Coupons with QR codes
- Confirmations with visual receipts
- Content requiring visual impact
Technical Limitations of SMS
1. Character Limit
SMS uses GSM-7 encoding, which allows 160 characters. But if you use special characters (emojis, accents), it switches to UCS-2/Unicode and the limit drops to 70 characters.
typescript
const message1 = "Your verification code is 123456";
const message2 = "Your code is 123456. Valid 5 min";
SMS Segment Table
| Encoding | Characters per SMS | Concatenated (per segment) |
|---|
Note: Long messages are divided into "segments" and each one counts as an individual SMS for billing.
2. Allowed GSM-7 Characters
text
A-Z, a-z, 0-9
@ ! " # $ % & ' ( ) + , - . / : ; < = > ?
Space, line break
Some special characters: [ ] \ ^ _ { | } ~
Characters that trigger Unicode:- Emojis
- Accented characters
- Special symbols
- Characters from other alphabets
3. Delivery Issues
SMS can fail for various reasons:
| Error Code | Meaning | Solution |
|---|
| 30001 | Invalid number | Validate E.164 format |
|---|
| 30002 | Number unreachable | Phone off/no coverage |
|---|
| 30003 | Number doesn't exist | Verify the number |
|---|
| 30004 | Spam detected | Review message content |
|---|
| 30005 | Carrier blocked | Register 10DLC (USA) |
|---|
| 30007 | Message filtered | Avoid spam words |
|---|
Important Regulations
In the United States: 10DLC
Since 2021, all A2P (Application-to-Person) messages in the USA require 10DLC registration:
Brand registration - Your company in The Campaign RegistryCampaign registration - Usage descriptionNumber assignment - Link numbers to campaignsWithout registration: Messages will be blocked or have very low delivery.
In the European Union: GDPR
- Explicit consent required
- Right to unsubscribe (STOP)
- Consent records
- Personal data protection
In Mexico: LFPDPPP
- Privacy notice required
- Consent for promotional messages
- Opt-out mechanism (STOP, CANCEL)
In Chile: Law 19.628
- Authorization from data owner
- Specific purpose of processing
- Right to cancellation
Sending SMS with Zavu
Installation
bash
npm install @zavudev/sdk
Configuration
typescript
import Zavudev from "@zavudev/sdk";
const client = new Zavu({
apiKey: process.env.ZAVU_API_KEY,
});
Send Simple SMS
typescript
const result = await client.messages.send({
to: "+14155551234",
channel: "sms",
text: "Your verification code is 847293. Valid for 5 minutes.",
});
console.log(Message sent: ${result.message.id});
console.log(Status: ${result.message.status});
typescript
const result = await client.messages.send({
to: "+14155551234",
channel: "sms",
text: "Your order #12345 has shipped. Arriving tomorrow.",
metadata: {
orderId: "12345",
userId: "user_abc",
type: "shipping_notification",
},
});
Send to Multiple Recipients
typescript
const recipients = ["+14155551234", "+14155555678", "+14155559012"];
const results = await Promise.all(
recipients.map((to) =>
client.messages.send({
to,
channel: "sms",
text: "Reminder: Your appointment is tomorrow at 10:00 AM.",
})
)
);
console.log(Sent: ${results.length} messages);
Common Use Cases
1. User Verification (OTP)
The most common use case. Conversion rate above 95%.
typescript
import Zavudev from "@zavudev/sdk";
const client = new Zavu();
async function sendOTP(phoneNumber: string): Promise<string> {
const code = Math.floor(100000 + Math.random() 900000).toString();
await client.messages.send({
to: phoneNumber,
channel: "sms",
text: Your verification code is ${code}. Expires in 5 minutes. Don't share it with anyone.,
});
return code;
}
const code = await sendOTP("+14155551234");
2. Order Confirmation
typescript
interface Order {
id: string;
customerPhone: string;
total: number;
items: number;
}
async function sendOrderConfirmation(order: Order) {
await client.messages.send({
to: order.customerPhone,
channel: "sms",
text: Order #${order.id} confirmed. Total: ${order.total}. ${order.items} items. We'll notify you when it ships.,
metadata: {
orderId: order.id,
type: "order_confirmation",
},
});
}
3. Appointment Reminder
typescript
interface Appointment {
id: string;
patientPhone: string;
doctorName: string;
date: Date;
location: string;
}
async function sendAppointmentReminder(apt: Appointment) {
const formattedDate = apt.date.toLocaleDateString("en-US", {
weekday: "long",
day: "numeric",
month: "long",
hour: "2-digit",
minute: "2-digit",
});
await client.messages.send({
to: apt.patientPhone,
channel: "sms",
text: Reminder: Appointment with Dr. ${apt.doctorName} on ${formattedDate} at ${apt.location}. Reply YES to confirm or NO to cancel.,
});
}
4. Security Alert
typescript
async function sendSecurityAlert(
phoneNumber: string,
eventType: "new_login" | "password_change" | "suspicious_activity",
details: { ip?: string; location?: string; device?: string }
) {
const messages = {
new_login: New login detected from ${details.location |
|---|
"unknown location"}. If this wasn't you, change your password immediately.,
password_change: Your password was changed successfully. If you didn't make this change, contact support immediately.,
suspicious_activity: We detected suspicious activity on your account. For security, please verify your recent transactions.,
};
await client.messages.send({
to: phoneNumber,
channel: "sms",
text: messages[eventType],
metadata: {
type: "security_alert",
eventType,
...details,
},
});
}
5. Shipping Notification
typescript
interface Shipment {
orderId: string;
customerPhone: string;
carrier: string;
trackingNumber: string;
estimatedDelivery: Date;
}
async function sendShippingNotification(shipment: Shipment) {
const deliveryDate = shipment.estimatedDelivery.toLocaleDateString("en-US", {
weekday: "long",
day: "numeric",
month: "long",
});
await client.messages.send({
to: shipment.customerPhone,
channel: "sms",
text: Your order #${shipment.orderId} is on its way! Tracking: ${shipment.trackingNumber} (${shipment.carrier}). Estimated delivery: ${deliveryDate}.,
});
}
Best Practices
Always use E.164 format (country code + number):
typescript
const phoneE164 = "+14155551234";
const phoneLocal = "4155551234";
const phoneWithSpaces = "+1 415 555 1234";
2. Message Content
typescript
const good = "Your code: 847293. Valid 5 min. Don't share it.";
const bad = "CONGRATULATIONS!!! You WON an INCREDIBLE PRIZE! Click NOW on this link to CLAIM your FREE GIFT!!!";
3. Include Opt-out
For marketing messages, always include opt-out option:
typescript
const marketingMessage =
Special offer: 20% off your next purchase.
Use code SUMMER20. Valid until 12/31.
Reply STOP to stop receiving offers.
.trim();
4. Handle Errors
typescript
async function sendSMSWithRetry(
to: string,
text: string,
maxRetries = 3
): Promise<boolean> {
for(let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await client.messages.send({
to,
channel: "sms",
text,
});
if (result.message.status === "queued") {
return true;
}
} catch (error) {
console.error(Attempt ${attempt} failed:, error);
if (attempt === maxRetries) {
throw new Error(SMS failed after ${maxRetries} attempts);
}
await new Promise(r => setTimeout(r, 1000 * attempt));
}
}
return false;
}
5. Validate Before Sending
typescript
function validateSMS(to: string, text: string): { valid: boolean; errors: string[] } {
const errors: string[] = [];
if (!/^\+[1-9]\d{6,14}$/.test(to)) {
errors.push("Number must be in E.164 format (+14155551234)");
}
if (text.length === 0) {
errors.push("Message cannot be empty");
}
if (text.length > 1600) {
errors.push("Message exceeds 10 SMS segments");
}
const hasUnicode = /[^\x00-\x7F]/.test(text);
if (hasUnicode && text.length > 70) {
errors.push("Message with special characters: multiple SMS will be sent");
}
return {
valid: errors.length === 0,
errors,
};
}
Costs and Optimization
Typical Cost Structure
| Component | Approximate Cost |
|---|
| Outbound SMS (USA) | $0.0079 - $0.02 |
|---|
| Outbound SMS (LATAM) | $0.02 - $0.08 |
|---|
| Outbound SMS (Europe) | $0.03 - $0.10 |
|---|
| Phone number | $1 - $5/month |
|---|
| Outbound MMS | $0.02 - $0.10 |
|---|
Tips to Reduce Costs
Use GSM-7 when possible - Avoid emojis and accents in critical messages - A 161 character message = 2 SMS
Concatenate messages intelligently - If you need >160 chars, make sure it's worth it
Validate numbers before sending - Avoid costs for invalid numbers - Use Zavu for number introspection
Consider alternatives for long content - WhatsApp for long messages (no per-character cost) - Email for extensive content
Use MAU-based pricing - With Zavu, you pay per active user, not per message - Unlimited sends to each user
SMS vs WhatsApp: When to Use Each
| Coverage | 99% phones | ~75% smartphones |
|---|
| Requires app | No | Yes |
|---|
| Requires internet | No | Yes |
|---|
| Cost | Per message | Per conversation |
|---|
| Rich content | No (MMS only) | Yes |
|---|
| Verification | Ideal | Good |
|---|
| Marketing | Limited | Excellent |
|---|
| Customer support | Basic | Complete |
|---|
Recommendations
- Use SMS for: OTP, critical alerts, users without WhatsApp
- Use WhatsApp for: Support, marketing, long conversations
- Use both: Automatic fallback if one fails
typescript
const result = await client.messages.send({
to: "+14155551234",
channel: "auto",
text: "Your code is 123456",
fallbackEnabled: true,
});
Webhook Integration
Receive real-time status updates:
typescript
app.post("/webhooks/zavu", (req, res) => {
const { event, data } = req.body;
switch (event) {
case "message.delivered":
console.log(SMS delivered: ${data.messageId});
break;
case "message.failed":
console.error(SMS failed: ${data.errorMessage});
break;
case "message.inbound":
console.log(SMS received from ${data.from}: ${data.text});
break;
}
res.sendStatus(200);
});
Conclusion
SMS and MMS remain fundamental tools in 2025:
- SMS: Ideal for verification, alerts, and critical notifications
- MMS: Useful for visual marketing when impact justifies the cost
Keys to success:Comply with local regulations (10DLC, GDPR, etc.)Optimize content to minimize segmentsAlways include opt-out optionValidate numbers before sendingImplement robust error handlingConsider WhatsApp as a complement, not a replacementAdditional Resources
Need help with SMS? Our team is available to assist you.
Contact us or join our
Discord community.