Saltar al contenido principal

Guía Next.js

Email, SMS y WhatsApp desde Next.js,
en una sola función de servidor.

Un archivo helper, llamado desde una Server Action o un Route Handler, envía el email de bienvenida, el SMS del pedido o el recordatorio por WhatsApp desde tu buzón, tu móvil y tu número. Sin código SMTP, sin coste por mensaje, y la clave nunca llega al navegador.

¿Con prisa? Resume este artículo con una IA

La respuesta corta

¿Cómo enviar email, SMS y WhatsApp desde Next.js gratis?

Pon un helper solo de servidor en lib/notify.ts que llame a POST /message de Unlimited Messaging y llámalo desde una Server Action o un Route Handler. La misma petición envía el email desde tu buzón, el SMS desde tu móvil Android y el WhatsApp desde tu número, y el plan Free no cobra nada por mensaje.

Lo habitual es un servicio por canal. Nodemailer es gratis pero solo habla SMTP, necesita el runtime de Node.js y te deja con el tope de tu buzón, 500 emails al día en Gmail. Una API de email como Resend es gratis hasta 3.000 emails al mes y 100 al día. El SMS con Twilio se cobra por segmento al acabar la prueba, que solo llega a 5 números verificados. WhatsApp es una cuarta integración.

Next.js ya te da los dos puntos de entrada de servidor que necesitas. Una Server Action gestiona tus formularios (registro, pago), un Route Handler atiende a otros clientes (un cron, un worker, otro servicio). Los dos se ejecutan en el servidor, donde las variables de entorno sin el prefijo NEXT_PUBLIC_ quedan fuera del bundle del navegador.

Desde Next.js 15.1, after() es estable: ejecuta código cuando la respuesta ya se ha enviado, así que el usuario nunca espera a que salga un email o un SMS.

Lee también: el SDK de TypeScript en detalle, y cómo conectar un buzón de Gmail con una contraseña de aplicación.

Ilustración: una petición JSON a POST /message que responde 201, con el titular «Email, SMS y WhatsApp desde Next.js».

Paso a paso

¿Cómo se añade a una app Next.js, paso a paso?

Cinco pasos, App Router, unos 10 minutos. Necesitas una cuenta gratis de Unlimited Messaging con al menos un canal conectado.

  1. Guarda la clave en el servidor

    Conecta tu buzón, tu número de WhatsApp o la app Android en Unlimited Messaging, crea una clave API y ponla en .env.local sin el prefijo NEXT_PUBLIC_. Next.js solo mete en el bundle del navegador las variables NEXT_PUBLIC_; las demás se quedan en el servidor.

    .env.local.env.local
    # .env.local (gitignored by create-next-app)
    # No NEXT_PUBLIC_ prefix: the key stays on the server
    UM_API_KEY=um_live_xxxx
    # Only for the internal route handler of step 4
    INTERNAL_SECRET=change-me-to-a-long-random-string
  2. Escribe un helper solo de servidor

    lib/notify.ts envuelve POST /message. import 'server-only' hace fallar el build si un componente cliente lo importa, así que la clave no puede filtrarse por error. Quita los canales sin destinatario y marca el mensaje como transaccional.

    lib/notify.tsTypeScript
    // lib/notify.ts
    import 'server-only'; // the build fails if a client component imports this file
    
    export type Channel = 'EMAIL' | 'WHATSAPP' | 'SMS';
    
    export async function notify(input: {
      email?: string;
      phone?: string; // E.164, e.g. +33612345678
      channels: Channel[];
      subject: string;
      text: string;
    }) {
      // Drop the channels that have no destination
      const channels = input.channels
        .filter((c) => (c === 'EMAIL' ? input.email : input.phone))
        .map((channel) => ({ channel }));
      if (channels.length === 0) return null;
    
      const res = await fetch('https://api.unlimitedmessaging.app/message', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.UM_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          to: { email: input.email, phone: input.phone },
          channels,
          subject: input.subject,
          text: input.text,
          priority: 'transactional',
        }),
      });
      if (!res.ok) throw new Error(`Unlimited Messaging ${res.status}: ${await res.text()}`);
      return res.json(); // { dispatchId, messages: [...] }
    }
  3. Llámalo desde una Server Action

    En el registro, envía el email y el WhatsApp de bienvenida dentro de after(): el formulario responde al instante y el mensaje sale justo después. Una Server Action acepta cualquier POST, así que valida la entrada y limita las peticiones como en un endpoint público.

    app/signup/actions.tsServer Action
    // app/signup/actions.ts
    'use server';
    
    import { after } from 'next/server';
    import { notify } from '@/lib/notify';
    
    export async function signUp(formData: FormData) {
      const email = String(formData.get('email'));
      const phone = String(formData.get('phone') ?? '') || undefined;
      // ...validate the input, rate limit, create the user
    
      // Runs after the response is sent: the form never waits for the message
      after(() =>
        notify({
          email,
          phone,
          channels: ['EMAIL', 'WHATSAPP'],
          subject: 'Welcome to Acme',
          text: 'Your account is ready. Reply to this message if you need help.',
        }).catch(console.error),
      );
    }
  4. O desde un Route Handler

    Para clientes fuera de tus formularios, un cron, un worker de cola, otro servicio, expón un Route Handler protegido por un secreto compartido. Aquí envía un email y un SMS desde tu móvil Android.

    app/api/notify/route.tsRoute Handler
    // app/api/notify/route.ts
    import { notify } from '@/lib/notify';
    
    export async function POST(req: Request) {
      // For your own jobs and services only, never a public endpoint
      if (req.headers.get('authorization') !== `Bearer ${process.env.INTERNAL_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      const { email, phone, subject, text } = await req.json();
      const result = await notify({ email, phone, channels: ['EMAIL', 'SMS'], subject, text });
      return Response.json(result);
    }
  5. Pruébalo

    Arranca next dev y llama a la ruta. La respuesta lista un mensaje por canal con su propio estado, agrupados por un dispatchId, y los mensajes aparecen en tu bandeja de Unlimited Messaging.

    Terminalcurl
    curl -X POST http://localhost:3000/api/notify \
      -H "Authorization: Bearer $INTERNAL_SECRET" \
      -H "Content-Type: application/json" \
      -d '{"email":"[email protected]","phone":"+33612345678",
           "subject":"Order #1042 shipped","text":"Your order #1042 is on its way."}'

Vibe coding

¿Programas con Cursor, v0 o Claude Code? Pega este prompt

El prompt le da a tu editor de IA el patrón seguro: un helper solo de servidor, la clave fuera de NEXT_PUBLIC_, after() para la velocidad. Te pide tus contactos de prueba antes de enviar nada.

Prompt para copiar
Añade el envío de mensajes transaccionales a este proyecto Next.js (App Router) con Unlimited Messaging: email, SMS y WhatsApp enviados desde mis propias cuentas.

1. Añade UM_API_KEY a .env.local y .env.example. No uses nunca un prefijo NEXT_PUBLIC_ y no leas nunca la clave en un componente cliente.
2. Crea lib/notify.ts empezando por import 'server-only'. Exporta notify({ email, phone, channels, subject, text }) que envía un POST https://api.unlimitedmessaging.app/message con la cabecera Authorization: Bearer UM_API_KEY y el JSON { to: { email, phone }, channels: [{ channel: 'EMAIL' | 'WHATSAPP' | 'SMS' }], subject, text, priority: 'transactional' }. Omite los canales sin destinatario; los números van en formato E.164.
3. Llama a notify desde mi Server Action de registro dentro de after() de next/server, para que el formulario no espere. Valida la entrada y mantén las comprobaciones de autenticación existentes.
4. Añade un Route Handler app/api/notify/route.ts protegido con Authorization: Bearer INTERNAL_SECRET para mis crons.
5. Referencia de la API: https://docs.unlimitedmessaging.app. Creo la clave API en https://app.unlimitedmessaging.app.

Enséñame el diff y pregúntame mi email y mi número de prueba antes de enviar nada.

Las opciones

Nodemailer, Resend, Twilio o una sola API: ¿qué encaja con Next.js?

Cuatro formas habituales de enviar mensajes transaccionales desde Next.js, comparadas por lo que envían, lo que es gratis y lo que mantienes.

Nodemailer, Resend, Twilio o una sola API: ¿qué encaja con Next.js?
Nodemailer + GmailLibrería SMTPResendAPI de emailTwilioAPI de SMS y WhatsAppUnlimited MessagingEmail, WhatsApp y SMS
CanalesEmailEmailSMS y WhatsApp, cobrados por mensajeEmail, WhatsApp y SMS en una petición
GratisLibrería gratis, Gmail limita a 500 emails al día3.000 emails al mes, 100 al díaPrueba: hasta 5 números verificadosPlan Free sin coste por mensaje
RuntimeSolo Node.js (sockets SMTP)Cualquier runtime (HTTP)Cualquier runtime (HTTP)Cualquier runtime (HTTP)
RemitenteTu buzónTu dominio verificadoUn número de Twilio o un remitente de WhatsApp registradoTu propio buzón, tu número de WhatsApp y tu móvil
Qué mantienesAjustes SMTP, errores, reintentosUn SDK, registros DNSUn SDK por producto, plantillas de Meta para WhatsAppUn solo fetch para todos los canales
Ideal paraUnos pocos emails desde tu buzónEmail en gran volumenSMS en volumen, WhatsApp oficialMensajes de una app uno a uno, gratis mientras creces

Comprobado el 9 de noviembre de 2026 en nodemailer.com, resend.com/pricing, la documentación de prueba de Twilio y la ayuda de Gmail (enlaces en las fuentes). Los planes gratis cambian: sigue los enlaces antes de construir sobre uno.

La letra pequeña

¿Cuáles son los límites?

Gratis quita la factura por mensaje y el código SMTP. No quita la seguridad, las reglas de WhatsApp ni el ritmo de un móvil.

  1. Una acción pública se puede abusar

    Una acción de registro que envía mensajes permite a cualquiera disparar un WhatsApp o un SMS a cualquier número. Añade un captcha o un límite de peticiones, y escribe a un número solo cuando sea de fiar.

  2. WhatsApp es no oficial, y el spam hace que bloqueen números

    Tu número se vincula como un dispositivo, fuera de la plataforma Business de Meta. Los mensajes que el usuario pidió son de bajo riesgo; los envíos masivos a desconocidos pueden hacer que bloqueen el número. Usa WhatsApp para lo transaccional.

  3. El SMS va al ritmo de un móvil

    Los SMS salen de la SIM de tu móvil Android, con tu tarifa. Android pide confirmación a partir de 30 SMS en 30 minutos, así que la app espacia los envíos a unos 30 cada 30 minutos, y el móvil tiene que estar encendido.

  4. El email sigue los límites de tu buzón

    Los emails salen de tu buzón por SMTP, así que se aplica su tope diario: 500 al día en una cuenta de Gmail. Para newsletters, usa un servicio de email masivo.

  5. Los mensajes del plan Free llevan una firma

    En el plan Free, los mensajes terminan con una línea corta "Sent with UnlimitedMessaging.app", y los archivos multimedia y los webhooks son de pago. Medium y Max quitan la línea.

  6. after() no es una cola

    Si la llamada falla después de enviar la respuesta, nada la reintenta. Para un recibo que no puedes perder, guarda la tarea en tu base de datos o en una cola y reintenta desde ahí.

FAQ

Preguntas sobre enviar mensajes desde Next.js

Ilian, ingeniero de software senior

Escrito por

· Ingeniero de software senior

Ingeniero de software senior, funda y dirige varias empresas tecnológicas. Diseña productos en torno a las API de mensajería, la automatización y la integración de la IA, y comparte aquí lo que aprende construyendo.

Ver el perfil de LinkedInActualizado el

Añade hoy email, SMS y WhatsApp a tu app Next.js.

Crea una cuenta gratis, conecta un buzón, un número de WhatsApp o un móvil Android y pega el helper. Sin tarjeta, sin coste por mensaje.