Aller au contenu principal

Guide Next.js

Email, SMS et WhatsApp depuis Next.js,
en une seule fonction serveur.

Un fichier helper, appelé depuis une Server Action ou un Route Handler, envoie l'email de bienvenue, le SMS de commande ou le rappel WhatsApp depuis votre boîte mail, votre téléphone et votre numéro. Pas de code SMTP, pas de frais par message, et la clé n'atteint jamais le navigateur.

Pressé ? Résumez cet article avec une IA

La réponse courte

Comment envoyer email, SMS et WhatsApp depuis Next.js gratuitement ?

Placez un helper côté serveur dans lib/notify.ts qui appelle POST /message sur Unlimited Messaging, puis appelez-le depuis une Server Action ou un Route Handler. La même requête envoie l'email depuis votre boîte mail, le SMS depuis votre téléphone Android et le WhatsApp depuis votre numéro, et le plan Free ne facture rien au message.

Le montage habituel, c'est un service par canal. Nodemailer est gratuit mais ne parle que SMTP, exige le runtime Node.js et vous laisse au plafond de votre boîte, 500 emails par jour sur Gmail. Une API email comme Resend est gratuite jusqu'à 3 000 emails par mois et 100 par jour. Le SMS via Twilio est facturé au segment après l'essai, qui ne joint que 5 numéros vérifiés. WhatsApp fait une quatrième intégration.

Next.js vous donne déjà les deux points d'entrée serveur nécessaires. Une Server Action gère vos formulaires (inscription, paiement), un Route Handler sert les autres appelants (une tâche cron, un worker, un autre service). Les deux tournent sur le serveur, où les variables d'environnement sans préfixe NEXT_PUBLIC_ restent hors du bundle navigateur.

Depuis Next.js 15.1, after() est stable : il exécute du code une fois la réponse envoyée, l'utilisateur n'attend donc jamais le départ d'un email ou d'un SMS.

À lire aussi : le SDK TypeScript en détail, et connecter une boîte Gmail avec un mot de passe d'application.

Illustration : une requête JSON vers POST /message qui répond 201, avec le titre « Email, SMS et WhatsApp depuis Next.js ».

Pas à pas

Comment l'ajouter à une app Next.js, étape par étape ?

Cinq étapes, App Router, environ 10 minutes. Il vous faut un compte Unlimited Messaging gratuit avec au moins un canal connecté.

  1. Gardez la clé côté serveur

    Connectez votre boîte mail, votre numéro WhatsApp ou l'application Android dans Unlimited Messaging, créez une clé API et placez-la dans .env.local sans préfixe NEXT_PUBLIC_. Next.js n'intègre au bundle navigateur que les variables NEXT_PUBLIC_ ; les autres restent sur le serveur.

    .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. Écrivez un helper réservé au serveur

    lib/notify.ts enveloppe POST /message. import 'server-only' fait échouer le build si un composant client l'importe, la clé ne peut donc pas fuiter par erreur. Il retire les canaux sans destinataire et marque le message comme transactionnel.

    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. Appelez-le depuis une Server Action

    À l'inscription, envoyez l'email et le WhatsApp de bienvenue dans after() : le formulaire répond tout de suite et le message part juste après. Une Server Action est accessible par n'importe quel POST : validez les entrées et limitez le débit comme pour un endpoint public.

    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. Ou depuis un Route Handler

    Pour les appelants hors de vos formulaires, une tâche cron, un worker, un autre service, exposez un Route Handler protégé par un secret partagé. Ici il envoie un email et un SMS depuis votre téléphone 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. Testez

    Lancez next dev et appelez la route. La réponse liste un message par canal avec son propre statut, regroupés par un dispatchId, et les messages apparaissent dans votre boîte de réception 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

Vous codez avec Cursor, v0 ou Claude Code ? Collez ce prompt

Le prompt donne à votre éditeur IA le bon schéma : un helper réservé au serveur, la clé hors NEXT_PUBLIC_, after() pour la rapidité. Il vous demande vos contacts de test avant tout envoi.

Prompt à copier
Ajoute l'envoi de messages transactionnels à ce projet Next.js (App Router) avec Unlimited Messaging : email, SMS et WhatsApp envoyés depuis mes propres comptes.

1. Ajoute UM_API_KEY dans .env.local et .env.example. N'utilise jamais de préfixe NEXT_PUBLIC_ et ne lis jamais la clé dans un composant client.
2. Crée lib/notify.ts qui commence par import 'server-only'. Exporte notify({ email, phone, channels, subject, text }) qui envoie un POST https://api.unlimitedmessaging.app/message avec l'en-tête Authorization: Bearer UM_API_KEY et le JSON { to: { email, phone }, channels: [{ channel: 'EMAIL' | 'WHATSAPP' | 'SMS' }], subject, text, priority: 'transactional' }. Ignore les canaux sans destinataire ; les numéros sont au format E.164.
3. Appelle notify depuis ma Server Action d'inscription dans after() de next/server, pour que le formulaire n'attende pas. Valide les entrées et garde les vérifications d'authentification existantes.
4. Ajoute un Route Handler app/api/notify/route.ts protégé par Authorization: Bearer INTERNAL_SECRET pour mes tâches cron.
5. Référence de l'API : https://docs.unlimitedmessaging.app. Je crée la clé API sur https://app.unlimitedmessaging.app.

Montre-moi le diff, puis demande-moi mon email et mon numéro de test avant d'envoyer quoi que ce soit.

Les options

Nodemailer, Resend, Twilio ou une seule API : quoi choisir pour Next.js ?

Quatre façons courantes d'envoyer des messages transactionnels depuis Next.js, comparées sur ce qu'elles envoient, ce qui est gratuit et ce que vous maintenez.

Nodemailer, Resend, Twilio ou une seule API : quoi choisir pour Next.js ?
Nodemailer + GmailBibliothèque SMTPResendAPI emailTwilioAPI SMS et WhatsAppUnlimited MessagingEmail, WhatsApp et SMS
CanauxEmailEmailSMS et WhatsApp, facturés au messageEmail, WhatsApp et SMS en une requête
GratuitBibliothèque gratuite, Gmail plafonne à 500 emails par jour3 000 emails par mois, 100 par jourEssai : 5 numéros vérifiés au maximumPlan Free sans frais par message
RuntimeNode.js uniquement (sockets SMTP)Tout runtime (HTTP)Tout runtime (HTTP)Tout runtime (HTTP)
ExpéditeurVotre boîte mailVotre domaine vérifiéUn numéro Twilio ou un expéditeur WhatsApp enregistréVotre boîte mail, votre numéro WhatsApp et votre téléphone
À maintenirRéglages SMTP, erreurs, nouvelles tentativesUn SDK, des enregistrements DNSUn SDK par produit, modèles Meta pour WhatsAppUn seul fetch pour tous les canaux
Idéal pourQuelques emails depuis votre boîteL'email en gros volumeLe SMS en volume, le WhatsApp officielLes messages d'une app un par un, gratuit pendant la croissance

Vérifié le 9 novembre 2026 sur nodemailer.com, resend.com/pricing, la documentation d'essai de Twilio et l'aide Gmail (liens dans les sources). Les offres gratuites changent : suivez les liens avant de construire dessus.

Les contreparties

Quelles sont les limites ?

Gratuit supprime la facture au message et le code SMTP. Pas la sécurité, les règles de WhatsApp ni le rythme d'un téléphone.

  1. Une action publique peut être détournée

    Une action d'inscription qui envoie des messages permet à n'importe qui de déclencher un WhatsApp ou un SMS vers n'importe quel numéro. Ajoutez un captcha ou une limite de débit, et n'écrivez à un numéro qu'une fois qu'il est fiable.

  2. WhatsApp est non officiel, et le spam fait bannir les numéros

    Votre numéro est lié comme un appareil, hors de la plateforme Business de Meta. Les messages demandés par l'utilisateur sont peu risqués ; des envois en masse à des inconnus peuvent faire bannir le numéro. Gardez WhatsApp pour le transactionnel.

  3. Le SMS va au rythme d'un téléphone

    Les SMS partent de la SIM de votre téléphone Android, sur votre forfait. Android demande une confirmation au-delà de 30 SMS en 30 minutes, l'application espace donc les envois à environ 30 toutes les 30 minutes, et le téléphone doit rester allumé.

  4. L'email suit les limites de votre boîte mail

    Les emails partent de votre boîte en SMTP, son plafond quotidien s'applique donc : 500 par jour sur un compte Gmail. Pour une newsletter, prenez un service d'emailing.

  5. Les messages du plan Free portent une signature

    Sur le plan Free, les messages se terminent par une courte ligne "Sent with UnlimitedMessaging.app", et les médias et les webhooks sont payants. Medium et Max retirent la ligne.

  6. after() n'est pas une file d'attente

    Si l'appel échoue après l'envoi de la réponse, rien ne le relance. Pour un reçu qu'il ne faut pas perdre, enregistrez la tâche en base ou dans une file et relancez depuis là.

FAQ

Questions sur l'envoi de messages depuis Next.js

Ilian, ingénieur logiciel senior

Écrit par

· Senior Software Engineer

Ingénieur logiciel senior, il fonde et dirige plusieurs sociétés tech. Il conçoit des produits autour des API de messagerie, de l’automatisation et de l’intégration de l’IA, et partage ici ce qu’il apprend en construisant.

Voir le profil LinkedInMis à jour le

Ajoutez email, SMS et WhatsApp à votre app Next.js aujourd'hui.

Créez un compte gratuit, connectez une boîte mail, un numéro WhatsApp ou un téléphone Android, collez le helper. Sans carte bancaire, sans frais par message.