Los SMS y MMS son las tecnologías de mensajería móvil más antiguas y universales del mundo. A pesar del auge de WhatsApp, Telegram y otras apps, siguen siendo fundamentales para verificación de usuarios, notificaciónes criticas y marketing. En esta guía te explicamos todo lo que necesitas saber como desarrollador.
Qué es un SMS?
SMS significa
Short Message Service (Servicio de Mensajes Cortos). Es un protocolo de comunicación que permite enviar mensajes de texto entre teléfonos móviles a través de la red celular.
Características Principales del SMS
| Longitud máxima | 160 caracteres (GSM-7) o 70 caracteres (Únicode) |
|---|
| Tipo de contenido | Solo texto |
|---|
| Requiere internet | No |
|---|
| Cobertura | 99% de teléfonos móviles |
|---|
| Tasa de apertura | ~98% |
|---|
Historia del SMS
- 1984: Primera propuesta del concepto SMS
- 1992: Primer SMS enviado ("Merry Christmas")
- 2000s: Explosion de uso entre consumidores
- 2010s: Transición hacia uso empresarial (A2P)
- 2020s: Fundamental para 2FA y notificaciones
Como Funciona Tecnicamente el SMS
Tu aplicación envía el mensaje a un proveedor de SMS (como Zavu)El proveedor se conecta a un SMSC (Short Message Service Center)El SMSC localiza la red del destinatarioLa torre celular entrega el mensaje al teléfonoEl teléfono recibe el mensaje sin necesidad de internettext
[Tu App] --> [API Zavu] --> [SMSC] --> [Red Celular] --> [Teléfono]
Qué es un MMS?
MMS significa
Multimedia Messaging Service (Servicio de Mensajería Multimedia). Es una extensión del SMS que permite enviar contenido multimedia.
Características del MMS
| Tamaño máximo | 300KB - 600KB (varia por operador) |
|---|
| Tipos de contenido | Imágenes, videos, audio, vCards |
|---|
| Requiere internet | Datos móviles |
|---|
| Cobertura | ~95% de smartphones |
|---|
| Costo | 3-5x más caro que SMS |
|---|
Tipos de contenido MMS
- Imágenes: JPG, PNG, GIF (hasta ~500KB)
- Video: MP4, 3GP (muy limitado, ~15 segundos)
- Audio: MP3, AAC (clips cortos)
- vCard: Tarjetas de contacto
- Texto largo: Mensajes sin límite de 160 caracteres
SMS vs MMS: Diferencias Clave
| Contenido | Solo texto | Multimedia + texto |
|---|
| Límite | 160 caracteres | ~600KB |
|---|
| Costo por mensaje | $0.01 - $0.03 | $0.03 - $0.10 |
|---|
| Requiere datos | No | Si |
|---|
| Velocidad entrega | Segundos | Segundos a minutos |
|---|
| Compatibilidad | Universal | Casi universal |
|---|
| Uso principal | 2FA, notificaciones | Marketing visual |
|---|
Cuando Usar SMS
- Verificación de usuarios (OTP/2FA)
- Notificaciones críticas (alertas de seguridad, confirmaciones)
- Recordatorios (citas, pagos, renovaciones)
- Alertas transacciónales (pedidos, envíos)
- Mercados con internet limitado
Cuando Usar MMS
- Campañas de marketing visual
- Promociones con imágenes de productos
- Cupones con código QR
- Confirmaciones con recibos visuales
- Contenido que requiere impacto visual
Limitaciones Técnicas del SMS
1. Límite de Caracteres
El SMS usa codificación GSM-7, que permite 160 caracteres. Pero si usas caracteres especiales (emojis, acentos como a, n, u), cambia a UCS-2/Único y el límite baja a 70 caracteres.
typescript
const mensaje1 = "Your verification code is 123456";
const mensaje2 = "Tu código es 123456. Valido 5 min";
Tabla de Segmentos SMS
| Codificación | Caracteres por SMS | Concatenados (por segmento) |
|---|
Nota: Los mensajes largos se dividen en "segmentos" y cada uno cuenta como un SMS individual para facturación.
2. Caracteres GSM-7 Permitidos
text
A-Z, a-z, 0-9
@ ! " # $ % & ' ( ) + , - . / : ; < = > ?
Espacio, salto de línea
Algunos caracteres especiales: [ ] \ ^ _ { | } ~
Caracteres que activan Únicode:- Emojis
- Caracteres acentuados (a, e, i, o, u, n)
- Simbolos especiales
- Caracteres de otros alfabetos
3. Problemas de Entrega
Los SMS pueden fallar por varias razones:
| Código Error | Significado | Solucion |
|---|
| 30001 | Número inválido | Validar formato E.164 |
|---|
| 30002 | Número no alcanzable | Teléfono apagado/sin cobertura |
|---|
| 30003 | Número no existe | Verificar el número |
|---|
| 30004 | Spam detectado | Revisar contenido del mensaje |
|---|
| 30005 | Carrier bloqueo | Registrar 10DLC (USA) |
|---|
| 30007 | Mensaje filtrado | Evitar palabras spam |
|---|
Regulaciónes Importantes
En Estados Unidos: 10DLC
Desde 2021, todos los mensajes A2P (Application-to-Person) en USA requieren registro 10DLC:
Registro de marca - Tu empresa en The Campaign RegistryRegistro de campaña - Descripción del usoAsignación de números - Vincular números a campañasSin registro: Los mensajes seran bloqueados o tendran muy baja entrega.
En Union Europea: GDPR
- Consentimiento explicito requerido
- Derecho a desuscribirse (STOP)
- Registro de consentimientos
- Protección de datos personales
En Mexico: LFPDPPP
- Aviso de privacidad requerido
- Consentimiento para mensajes promociónales
- Mecanismo de baja (STOP, CANCELAR)
En Chile: Ley 19.628
- Autorizacion del titular de datos
- Finalidad específica del tratamiento
- Derecho a cancelación
Enviando SMS con Zavu
Instalacion
bash
npm install @zavudev/sdk
Configuración
typescript
import Zavudev from "@zavudev/sdk";
const client = new Zavu({
apiKey: process.env.ZAVU_API_KEY,
});
Enviar SMS Simple
typescript
const result = await client.messages.send({
to: "+56912345678",
channel: "sms",
text: "Tu código de verificación es 847293. Valido por 5 minutos.",
});
console.log(Mensaje enviado: ${result.message.id});
console.log(Estado: ${result.message.status});
typescript
const result = await client.messages.send({
to: "+56912345678",
channel: "sms",
text: "Tu pedido #12345 ha sido enviado. Llegara manana.",
metadata: {
orderId: "12345",
userId: "user_abc",
type: "shipping_notification",
},
});
Enviar a Múltiples Destinatarios
typescript
const recipients = ["+56912345678", "+56987654321", "+56911223344"];
const results = await Promise.all(
recipients.map((to) =>
client.messages.send({
to,
channel: "sms",
text: "Recordatorio: Tu cita es manana a las 10:00 AM.",
})
)
);
console.log(Enviados: ${results.length} mensajes);
Casos de Uso Comúnes
1. Verificación de Usuario (OTP)
El caso de uso más común. Tasa de conversión superior al 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: Tu código de verificación es ${code}. Expira en 5 minutos. No lo compartas con nadie.,
});
return code;
}
const code = await sendOTP("+56912345678");
2. Confirmación de Pedido
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: Pedido #${order.id} confirmado. Total: ${order.total}. ${order.items} artículos. Te avisaremos cuando se envie.,
metadata: {
orderId: order.id,
type: "order_confirmation",
},
});
}
3. Recordatorio de Cita
typescript
interface Appointment {
id: string;
patientPhone: string;
doctorName: string;
date: Date;
location: string;
}
async function sendAppointmentReminder(apt: Appointment) {
const formattedDate = apt.date.toLocaleDateString("es-CL", {
weekday: "long",
day: "numeric",
month: "long",
hour: "2-digit",
minute: "2-digit",
});
await client.messages.send({
to: apt.patientPhone,
channel: "sms",
text: Recordatorio: Cita con Dr. ${apt.doctorName} el ${formattedDate} en ${apt.location}. Responde SI para confirmar o NO para cancelar.,
});
}
4. Alerta de Seguridad
typescript
async function sendSecurityAlert(
phoneNumber: string,
eventType: "new_login" | "password_change" | "suspicious_activity",
details: { ip?: string; location?: string; device?: string }
) {
const messages = {
new_login: Nuevo inicio de sesión detectado desde ${details.location |
|---|
"ubicación desconocida"}. Si no fuiste tu, cambia tu contrasena inmediatamente.,
password_change: Tu contrasena fue cambiada éxitosamente. Si no realizaste este cambio, contacta soporte inmediatamente.,
suspicious_activity: Detectamos actividad sospechosa en tu cuenta. Por seguridad, verifica tus últimas transacciones.,
};
await client.messages.send({
to: phoneNumber,
channel: "sms",
text: messages[eventType],
metadata: {
type: "security_alert",
eventType,
...details,
},
});
}
5. Notificación de Envio
typescript
interface Shipment {
orderId: string;
customerPhone: string;
carrier: string;
trackingNumber: string;
estimatedDelivery: Date;
}
async function sendShippingNotification(shipment: Shipment) {
const deliveryDate = shipment.estimatedDelivery.toLocaleDateString("es-CL", {
weekday: "long",
day: "numeric",
month: "long",
});
await client.messages.send({
to: shipment.customerPhone,
channel: "sms",
text: Tu pedido #${shipment.orderId} esta en camino! Seguimiento: ${shipment.trackingNumber} (${shipment.carrier}). Llegada estimada: ${deliveryDate}.,
});
}
Mejores Prácticas
Siempre usa formato E.164 (código de país + número):
typescript
const phoneE164 = "+56912345678";
const phoneLocal = "912345678";
const phoneWithSpaces = "+56 9 1234 5678";
2. Contenido del Mensaje
typescript
const good = "Tu código: 847293. Valido 5 min. No lo compartas.";
const bad = "FELICIDADES!!! Has GANADO un PREMIO INCREIBLE! Haz clic AHORA en este link para RECLAMAR tu REGALO GRATIS!!!";
3. Incluir Opt-out
Para mensajes de marketing, siempre incluye opcion de baja:
typescript
const marketingMessage =
Oferta especial: 20% de descuento en tu próxima compra.
Usa código VERANO20. Valido hasta el 31/12.
Responde STOP para no recibir más ofertas.
.trim();
4. Manejar Errores
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(Intento ${attempt} fallido:, error);
if (attempt === maxRetries) {
throw new Error(SMS fallido después de ${maxRetries} intentos);
}
await new Promise(r => setTimeout(r, 1000 * attempt));
}
}
return false;
}
5. Validar Antes de Enviar
typescript
function válidateSMS(to: string, text: string): { valid: boolean; errors: string[] } {
const errors: string[] = [];
if (!/^\+[1-9]\d{6,14}$/.test(to)) {
errors.push("Número debe estar en formato E.164 (+56912345678)");
}
if (text.length === 0) {
errors.push("El mensaje no puede estar vacio");
}
if (text.length > 1600) {
errors.push("El mensaje excede 10 segmentos SMS");
}
const hasÚnicode = /[^\x00-\x7F]/.test(text);
if (hasÚnicode && text.length > 70) {
errors.push("Mensaje con caracteres especiales: se enviaran múltiples SMS");
}
return {
valid: errors.length === 0,
errors,
};
}
Costos y Optimización
Estructura de Costos Típica
| Componente | Costo Apróximado |
|---|
| SMS saliente (USA) | $0.0079 - $0.02 |
|---|
| SMS saliente (LATAM) | $0.02 - $0.08 |
|---|
| SMS saliente (Europa) | $0.03 - $0.10 |
|---|
| Número telefónico | $1 - $5/mes |
|---|
| MMS saliente | $0.02 - $0.10 |
|---|
Consejos para Reducir Costos
Usa GSM-7 cuando sea posible - Evita emojis y acentos en mensajes criticos - Un mensaje de 161 caracteres = 2 SMS
Concatena mensajes inteligentemente - Si necesitas >160 chars, asegurate que valga la pena
Valida números antes de enviar - Evita costos por números inválidos - Usa Zavu para introspection de números
Considera alternativas para contenido largo - WhatsApp para mensajes largos (sin costo por caracter) - Email para contenido extenso
Usa MAU-based pricing - Con Zavu, pagas por usuario activo, no por mensaje - Envíos ilimitados a cada usuario
SMS vs WhatsApp: Cuando Usar Cada Uno
| Cobertura | 99% teléfonos | ~75% smartphones |
|---|
| Requiere app | No | Si |
|---|
| Requiere internet | No | Si |
|---|
| Costo | Por mensaje | Por conversación |
|---|
| Contenido rico | No (solo MMS) | Si |
|---|
| Verificación | Ideal | Bueno |
|---|
| Marketing | Limitado | Excelente |
|---|
| Soporte al cliente | Básico | Completo |
|---|
Recomendaciones
- Usa SMS para: OTP, alertas criticas, usuarios sin WhatsApp
- Usa WhatsApp para: Soporte, marketing, conversaciones largas
- Usa ambos: Fallback automático si uno falla
typescript
const result = await client.messages.send({
to: "+56912345678",
channel: "auto",
text: "Tu código es 123456",
fallbackEnabled: true,
});
Integración con Webhooks
Recibe actualizaciones de estado en tiempo real:
typescript
app.post("/webhooks/zavu", (req, res) => {
const { event, data } = req.body;
switch (event) {
case "message.delivered":
console.log(SMS entregado: ${data.messageId});
break;
case "message.failed":
console.error(SMS fallido: ${data.errorMessage});
break;
case "message.inbound":
console.log(SMS recibido de ${data.from}: ${data.text});
break;
}
res.sendStatus(200);
});
Conclusion
SMS y MMS siguen siendo herramientas fundamentales en 2025:
- SMS: Ideal para verificación, alertas y notificaciónes criticas
- MMS: Util para marketing visual cuando el impacto justifica el costo
Claves para el éxito:Cumple con regulaciónes locales (10DLC, GDPR, etc.)Optimiza el contenido para minimizar segmentosIncluye siempre opcion de opt-outValida números antes de enviarImplementa manejo de errores robustoConsidera WhatsApp como complemento, no reemplazoRecursos Adicionales
Necesitas ayuda con SMS? Nuestro equipo esta disponible para asistirte.
Contáctaños o unete a nuestra
comúnidad en Discord.