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
| Characteristic | Value |
|---|---|
| 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 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
| Characteristic | Value |
|---|---|
| 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
| Aspect | SMS | MMS |
|---|---|---|
| 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// This message uses 1 SMS (GSM-7) const message1 = "Your verification code is 123456"; // This message uses 2 SMS (Unicode due to emoji) const message2 = "Your code is 123456. Valid 5 min";
SMS Segment Table
| Encoding | Characters per SMS | Concatenated (per segment) |
|---|---|---|
| GSM-7 | 160 | 153 |
| Unicode | 70 | 67 |
Note: Long messages are divided into "segments" and each one counts as an individual SMS for billing.
2. Allowed GSM-7 Characters
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:
Without 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
terminalnpm install @zavudev/sdk
Configuration
TypeScriptimport Zavudev from "@zavudev/sdk"; const client = new Zavu({ apiKey: process.env.ZAVU_API_KEY, });
Send Simple SMS
TypeScriptconst result = await client.messages.send({ to: "+14155551234", channel: "sms", text: "Your verification code is 847293. Valid for 5 minutes.", }); console.log(); console.log(Message sent:${result.message.id}Status:${result.message.status});
Send SMS with Metadata
TypeScriptconst 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
TypeScriptconst 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%.
TypeScriptimport 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:, }); return code; } // Usage const code = await sendOTP("+14155551234"); // Store 'code' in cache (Redis) with 5 minute TTLYour verification code is${code}. Expires in 5 minutes. Don't share it with anyone.
2. Order Confirmation
TypeScriptinterface Order { id: string; customerPhone: string; total: number; items: number; } async function sendOrderConfirmation(order: Order) { await client.messages.send({ to: order.customerPhone, channel: "sms", text:, metadata: { orderId: order.id, type: "order_confirmation", }, }); }Order #${order.id} confirmed. Total: $${order.total}. ${order.items} items. We'll notify you when it ships.
3. Appointment Reminder
TypeScriptinterface 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
TypeScriptasync function sendSecurityAlert( phoneNumber: string, eventType: "new_login" | "password_change" | "suspicious_activity", details: { ip?: string; location?: string; device?: string } ) { const messages = { new_login:, password_change:New login detected from${details.location || "unknown location"}. If this wasn't you, change your password immediately.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
TypeScriptinterface 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
1. Number Format
Always use E.164 format (country code + number):
TypeScript// Correct const phoneE164 = "+14155551234"; // Incorrect const phoneLocal = "4155551234"; const phoneWithSpaces = "+1 415 555 1234";
2. Message Content
TypeScript// GOOD: Concise, clear, with CTA const good = "Your code: 847293. Valid 5 min. Don't share it."; // BAD: Too long, spam-like 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:
TypeScriptconst 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
TypeScriptasync 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(, error); if (attempt === maxRetries) { throw new Error(Attempt${attempt} failed:SMS failed after${maxRetries} attempts); } // Wait before retrying (exponential backoff) await new Promise(r => setTimeout(r, 1000 * attempt)); } } return false; }
5. Validate Before Sending
TypeScriptfunction validateSMS(to: string, text: string): { valid: boolean; errors: string[] } { const errors: string[] = []; // Validate E.164 format if (!/^\+[1-9]\d{6,14}$/.test(to)) { errors.push("Number must be in E.164 format (+14155551234)"); } // Validate length if (text.length === 0) { errors.push("Message cannot be empty"); } if (text.length > 1600) { errors.push("Message exceeds 10 SMS segments"); } // Unicode warning 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.0083 - $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
SMS vs WhatsApp: When to Use Each
| Criteria | SMS | |
|---|---|---|
| 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// Example: Send with automatic fallback const result = await client.messages.send({ to: "+14155551234", channel: "auto", // Zavu chooses the best channel text: "Your code is 123456", fallbackEnabled: true, // If WhatsApp fails, use SMS });
Webhook Integration
Receive real-time status updates:
TypeScript// Your webhook endpoint app.post("/webhooks/zavu", (req, res) => { const { event, data } = req.body; switch (event) { case "message.delivered": console.log(); break; case "message.failed": console.error(SMS delivered:${data.messageId}SMS failed:${data.errorMessage}); // Retry or notify break; case "message.inbound": console.log(SMS received from${data.from}: ${data.text}); // Process response (e.g.: STOP, YES, NO) 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:
Additional Resources
- SMS for Developers - Complete documentation
- WhatsApp for Developers - Alternative for rich messaging
Need help with SMS? Our team is available to assist you. Contact us or join our Discord community.