code examples

Sent logo
Sent TeamMar 8, 2026 / code examples / Article

Send MMS with Vonage Messages API: Complete Node.js Express Guide

Learn how to send MMS messages with images using Vonage Messages API, Node.js 20/22 LTS, and Express 5.x. Complete guide covering setup, A2P 10DLC registration, authentication, error handling, and troubleshooting for production MMS messaging.

Send MMS with Vonage Messages API: Complete Node.js Express Guide

Build a Node.js application using Express to send Multimedia Messaging Service (MMS) messages via the Vonage Messages API. Learn how to send MMS with images using Node.js 20/22 LTS, Express 5.x, and the Vonage Server SDK. Master project setup, core implementation, API creation, Vonage integration, A2P 10DLC registration, error handling, security, troubleshooting, and testing.

By the end of this guide, you'll have a functional Express API endpoint that accepts requests and sends MMS messages containing images to specified US phone numbers.

Project Overview and Goals

Goal: Create a simple, robust Node.js backend service that exposes an API endpoint to send MMS messages using the Vonage Messages API.

Problem Solved: Send rich media content (images) via MMS programmatically, enhancing user engagement compared to standard SMS. Use this for notifications, alerts, marketing campaigns, or interactive applications requiring visual content.

Technologies:

  • Node.js: JavaScript runtime for server-side applications. Event-driven architecture, large ecosystem (npm), and well-suited for I/O-bound tasks like API interactions.
  • Express: Minimal, flexible Node.js web framework. Simple route setup, middleware handling, and HTTP request/response management.
  • Vonage Messages API: Unified API for sending messages across various channels (SMS, MMS). Specific MMS capabilities for US numbers with comprehensive developer support.
  • dotenv: Module to load environment variables from .env file into process.env. Securely manage sensitive credentials outside the codebase.

System Architecture:

text
+-------------+        +------------------------+        +----------------+        +-----------------+
|   Client    | -----> | Node.js/Express API    | -----> | Vonage Messages| -----> | Recipient Phone |
| (e.g., Web, |        | (This Application)     |        | API            |        | (US Number)     |
| Mobile App) |        | - POST /send-mms       |        +----------------+        +-----------------+
|             |        | - Uses Vonage SDK      |
+-------------+        +------------------------+
                         |
                         | Uses Credentials from .env
                         | (API Key/Secret, App ID, Private Key)
                         |
                         V
                       +------------------------+
                       | Vonage Application     |
                       | (Dashboard Config)     |
                       | - Linked Number        |
                       | - Webhook URLs         |
                       +------------------------+

Prerequisites:

  • Node.js and npm (or yarn): Node.js 20.x LTS or 22.x LTS recommended (as of 2025). Download from nodejs.org. Node.js 18.x reaches end-of-life in April 2025.
  • Vonage API Account: Sign up at Vonage API Dashboard. Receive free credit for testing.
  • A2P 10DLC Registration (Required for US Production): Complete 10DLC Brand and Campaign registration through the Vonage Dashboard for production A2P messaging in the US. Mandatory for all A2P SMS/MMS traffic from US long code numbers as of 2025. Trial accounts may have limited sending capabilities until registration is complete.
  • Vonage Phone Number: US-based Vonage virtual number capable of sending SMS and MMS. Purchase via Vonage Dashboard (Numbers > Buy Numbers). Note: MMS sending is generally restricted to US numbers and Application-to-Person (A2P) use cases.
  • Publicly Accessible Image URL: Host the image online and make it accessible via public URL (CDN, public cloud storage bucket, or image hosting service). Supported formats: .jpg, .jpeg, .png.
  • (Recommended for Local Development) ngrok: Expose your local development server to the internet. While not strictly needed if you only send messages without processing webhooks, it's practically required for initial Vonage Application setup in the dashboard (Section 4), which mandates webhook URLs. Download from ngrok.com.

1. Set Up Your Node.js Express MMS Project

Initialize the Node.js project and install necessary dependencies.

  1. Create Project Directory: Open your terminal and create a new directory for your project. Navigate into it.

    bash
    mkdir vonage-mms-sender
    cd vonage-mms-sender
  2. Initialize Node.js Project: Create a package.json file to manage project dependencies and scripts. The -y flag accepts default settings.

    bash
    npm init -y
  3. Install Dependencies:

    • @vonage/server-sdk: Official Vonage SDK for Node.js (includes Messages API client). Latest version as of 2025: 3.24.1.
    • express: Web framework for building the API. Express 5.x (released October 2024) recommended for new projects with Node.js 18+. This guide works with both Express 4.x and 5.x.
    • dotenv: Load environment variables from .env file.
    bash
    npm install @vonage/server-sdk express dotenv

    Note: Express 5.x requires Node.js 18 or higher and includes security improvements such as updated path-to-regexp@8.x for ReDoS mitigation. The code examples work with both Express 4.x and 5.x without modification.

  4. Create Project Files: Create the main application file and environment variables file.

    bash
    # Linux/macOS
    touch index.js .env .gitignore
    
    # Windows (Command Prompt)
    type nul > index.js
    type nul > .env
    type nul > .gitignore
    
    # Windows (PowerShell)
    New-Item index.js -ItemType File
    New-Item .env -ItemType File
    New-Item .gitignore -ItemType File
  5. Configure .gitignore: Add node_modules and .env to prevent committing dependencies and sensitive credentials to version control.

    text
    # .gitignore
    
    node_modules/
    .env
    *.log
    private.key # If stored directly in project (see security note)
    • Security Note: Storing private.key directly in project root is for initial local testing only. Not secure and must not be done in production. See Section 7 (Security Features) and Section 12 (Deployment and CI/CD) for secure handling methods in production environments.
  6. Project Structure: Your initial project structure:

    text
    vonage-mms-sender/
    ├── node_modules/
    ├── .env
    ├── .gitignore
    ├── index.js
    ├── package-lock.json
    └── package.json

2. Implement MMS Sending with Vonage Messages API

Encapsulate the MMS sending logic within a dedicated function for reusability and clarity.

  1. Modify index.js: Open index.js and import necessary modules, then set up the Vonage client configuration.

    javascript
    // index.js
    require('dotenv').config(); // Load environment variables from .env file
    const express = require('express');
    const { Vonage } = require('@vonage/server-sdk');
    const { Messages } = require('@vonage/messages'); // Import Messages capability
    
    // Basic validation for essential environment variables
    const requiredEnv = [
        'VONAGE_API_KEY',
        'VONAGE_API_SECRET',
        'VONAGE_APPLICATION_ID',
        'VONAGE_PRIVATE_KEY_PATH',
        'VONAGE_SENDER_NUMBER'
    ];
    
    for (const variable of requiredEnv) {
        if (!process.env[variable]) {
            console.error(`Error: Environment variable ${variable} is not set.`);
            process.exit(1); // Exit if essential config is missing
        }
    }
    
    // Initialize Vonage Client using Application ID and Private Key for Messages API v1
    // This authentication method is required for MMS via Messages API v1.
    const vonage = new Vonage({
        apiKey: process.env.VONAGE_API_KEY, // Optional for Messages API v1, but good practice
        apiSecret: process.env.VONAGE_API_SECRET, // Optional for Messages API v1, but good practice
        applicationId: process.env.VONAGE_APPLICATION_ID,
        privateKey: process.env.VONAGE_PRIVATE_KEY_PATH
    });
    
    // Create a specific client instance for the Messages API
    const messagesClient = new Messages(vonage.credentials);
    
    // --- MMS Sending Function ---
    async function sendMmsMessage(recipientNumber, imageUrl, caption = '') {
        console.log(`Attempting to send MMS to: ${recipientNumber} with image: ${imageUrl}`);
    
        try {
            const response = await messagesClient.send({
                message_type: "image", // Specify message type as image for MMS
                to: recipientNumber,   // E.164 format recommended (e.g., 14155550100 or +14155550100)
                from: process.env.VONAGE_SENDER_NUMBER, // Your Vonage US number in E.164 format
                channel: "mms",        // Specify channel as MMS
                image: {               // Image object
                    url: imageUrl,     // Publicly accessible URL of the image
                    caption: caption   // Optional caption text
                }
            });
    
            console.log('MMS Sent Successfully:', response);
            // Expected successful response format: { message_uuid: '...' }
            return { success: true, message_uuid: response.message_uuid };
    
        } catch (error) {
            console.error('Error sending MMS:', error?.response?.data || error.message || error);
            // Log the detailed error from Vonage if available
            let errorMessage = 'Failed to send MMS.';
            if (error?.response?.data?.title) {
                errorMessage = `${error.response.data.title}: ${error.response.data.detail || ''}`;
            } else if (error.message) {
                errorMessage = error.message;
            }
            return { success: false, error: errorMessage };
        }
    }
    
    // --- (API Layer will be added below) ---
  2. Explanation:

    • require('dotenv').config(): Loads variables from .env file.
    • Imports express, Vonage (main SDK), and Messages (specific capability).
    • Environment Variable Validation: Simple loop checks if critical environment variables are set, exiting gracefully if not. Prevents runtime errors from missing configuration.
    • Vonage Client Initialization: Initialize the main Vonage client. For Messages API v1 (required for MMS currently), authentication must use applicationId and privateKey. While apiKey and apiSecret aren't strictly needed for Messages API v1 auth, including them doesn't hurt and might be useful for other Vonage APIs.
    • Messages Client: Create a dedicated messagesClient instance using credentials from the main vonage object. This client is specifically designed for the Messages API.
    • sendMmsMessage Function:
      • Takes recipientNumber, imageUrl, and optional caption as input.
      • Uses async/await for cleaner handling of the promise returned by messagesClient.send.
      • Calls messagesClient.send with specific payload structure for MMS:
        • message_type: Must be "image".
        • to: Recipient's phone number in E.164 format (e.g., 14155550100 for US numbers, or with optional + prefix: +14155550100). E.164 is the international telephone numbering standard: [country code][area code][local number] with no spaces or special characters.
        • from: Your Vonage US number linked to the application.
        • channel: Must be "mms".
        • image: Object containing url (required) and optional caption.
      • Includes try...catch for robust error handling. Logs success or detailed errors (accessing nested properties like error?.response?.data for specific Vonage API error details).
      • Returns an object indicating success (true/false) and either the message_uuid or an error message.

3. Build an Express API Endpoint for MMS

Use Express to create an HTTP endpoint that utilizes the sendMmsMessage function.

  1. Add Express Setup and Route to index.js: Append this code to index.js, below the sendMmsMessage function definition.

    javascript
    // index.js (continued)
    
    // --- Express API Setup ---
    const app = express();
    const PORT = process.env.PORT || 3000; // Use port from .env or default to 3000
    
    // Middleware to parse JSON request bodies
    app.use(express.json());
    // Middleware to parse URL-encoded request bodies
    app.use(express.urlencoded({ extended: true }));
    
    // --- API Endpoint to Send MMS ---
    app.post('/send-mms', async (req, res) => {
        const { recipient, imageUrl, caption } = req.body;
    
        // Basic Input Validation
        if (!recipient || !imageUrl) {
            console.warn('Validation Error: Missing recipient or imageUrl in request body.');
            return res.status(400).json({
                success: false,
                error: 'Missing required fields: recipient and imageUrl are required.'
            });
        }
    
        // Validate Image URL format (simple check)
        if (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://')) {
             console.warn(`Validation Error: Invalid image URL format: ${imageUrl}`);
             return res.status(400).json({
                 success: false,
                 error: 'Invalid image URL format. URL must start with http:// or https://'
             });
        }
    
        // Basic Phone Number Format Check (adjust regex as needed for stricter validation)
        // This regex checks for optional '+' and digits. More robust validation might be needed.
        const phoneRegex = /^\+?[1-9]\d{1,14}$/; // Basic E.164-like format check (+optional, digits). Not exhaustive.
        if (!phoneRegex.test(recipient)) {
             console.warn(`Validation Error: Invalid recipient phone number format: ${recipient}`);
             return res.status(400).json({
                 success: false,
                 error: 'Invalid recipient phone number format. Use E.164 format (e.g., +14155550100).'
             });
        }
    
        console.log(`Received request to send MMS to ${recipient}`);
    
        const result = await sendMmsMessage(recipient, imageUrl, caption);
    
        if (result.success) {
            console.log(`MMS successfully initiated for ${recipient}. Message UUID: ${result.message_uuid}`);
            res.status(200).json({
                success: true,
                message: 'MMS sending initiated successfully.',
                message_uuid: result.message_uuid
            });
        } else {
            console.error(`Failed to send MMS to ${recipient}: ${result.error}`);
            // Send a generic error message to the client, log the specific error internally
            res.status(500).json({
                success: false,
                error: 'Failed to send MMS. Check server logs for details.'
                // Avoid sending detailed internal errors (like Vonage API errors) to the client
                // detailed_error: result.error // Potentially expose internal info, use with caution
            });
        }
    });
    
    // --- Root Endpoint for Health Check ---
    app.get('/', (req, res) => {
        res.status(200).send('Vonage MMS Sender API is running!');
    });
    
    // --- Start the Server ---
    app.listen(PORT, () => {
        console.log(`Server listening on port ${PORT}`);
        console.log(`API Endpoint available at http://localhost:${PORT}/send-mms (POST)`);
    });
  2. Explanation:

    • Express Initialization: Creates an Express application instance.
    • Port: Defines the port number, preferring the PORT environment variable if set, otherwise defaulting to 3000.
    • Middleware:
      • express.json(): Parses incoming requests with JSON payloads (needed for req.body).
      • express.urlencoded(): Parses incoming requests with URL-encoded payloads.
    • /send-mms Endpoint (POST):
      • Defines a route that listens for POST requests at /send-mms.
      • Extracts recipient, imageUrl, and optional caption from request body (req.body).
      • Input Validation: Performs basic checks:
        • Ensures recipient and imageUrl are present.
        • Checks if imageUrl starts with http:// or https://.
        • Uses simple regex (phoneRegex) to validate basic phone number structure. Note: Robust E.164 validation is complex; this is a basic check. Error message guides users toward the preferred E.164 format.
        • Returns 400 Bad Request status with error message if validation fails.
      • Calls sendMmsMessage function with validated inputs.
      • Responds to client based on result from sendMmsMessage:
        • On success: Sends 200 OK status with message_uuid.
        • On failure: Sends 500 Internal Server Error status with generic error message. Crucial not to expose detailed internal Vonage error messages directly to client for security reasons. Log detailed error server-side.
    • / Endpoint (GET): Simple root endpoint for basic health checks or landing page.
    • app.listen: Starts Express server, making it listen for incoming connections on specified PORT. Logs confirmation messages to console.

4. Configure Vonage Dashboard for MMS Messaging

Configure your Vonage account and link it to your application code via credentials.

  1. Log in to Vonage API Dashboard: Access your dashboard at dashboard.nexmo.com.

  2. Create a Vonage Application:

    • Navigate to "Applications" in the left-hand menu and click "Create a new application".
    • Name: Give your application a descriptive name (e.g., "Node Express MMS Sender").
    • Capabilities: Find the "Messages" capability and toggle it ON.
    • Webhooks (Inbound & Status): Provide URLs for both "Inbound URL" and "Status URL" when enabling the Messages capability.
      • Why? Even if this simple sender application doesn't process incoming messages or status updates, Vonage requires valid, publicly accessible URLs during setup for the Messages capability. The platform uses these endpoints to report message delivery statuses and handle incoming messages directed to your linked number. Without valid URLs that respond with 200 OK, the platform might retry sending webhook data, and application setup might fail or behave unexpectedly.
      • Therefore, for local development and testing that involves setting up the application in the Vonage dashboard, a tool like ngrok becomes practically necessary to provide these required URLs.
      • Development: Use ngrok to get a public URL for your local server. If your app runs on port 3000, start ngrok: ngrok http 3000. Copy the https:// forwarding URL provided by ngrok (e.g., https://<unique-code>.ngrok.io).
        • Inbound URL: https://<unique-code>.ngrok.io/webhooks/inbound (Even if you don't implement this route yet)
        • Status URL: https://<unique-code>.ngrok.io/webhooks/status (Even if you don't implement this route yet)
      • Production: Replace these with actual public URLs of your deployed application's webhook handlers.
      • Placeholder (Alternative): Use a service like Mockbin to generate URLs that simply return a 200 OK status. This is sufficient if you only need to send and don't care about status/inbound webhooks for now.
    • Generate Public/Private Key: Click "Generate public and private key" link.
      • A public key will be added to application settings.
      • A private.key file will be automatically downloaded. Save this file securely. For this guide, move it into your project's root directory (vonage-mms-sender/private.key). Remember to add private.key to your .gitignore.
    • Click "Generate new application".
  3. Note Application ID: After creation, you'll be taken to the application's details page. Copy the Application ID.

  4. Link Your Vonage Number:

    • Scroll down to "Linked numbers" section on the application details page.
    • Find your US MMS-capable Vonage number and click "Link" button next to it. If you don't have one, click "Buy numbers". Linking ensures messages sent from this number use this application's settings (including authentication) and incoming messages to this number trigger the Inbound webhook.
  5. Get API Key and Secret:

    • Click your username/profile icon in the top-right corner of the dashboard or navigate to the main dashboard overview page.
    • Your API Key and API Secret are displayed near the top. Copy both.
  6. Configure .env File: Open .env file in your project and add the credentials you just gathered.

    dotenv
    # .env - Vonage Credentials and Configuration
    
    # Vonage API Credentials (Found on Dashboard Home)
    VONAGE_API_KEY=YOUR_API_KEY_HERE
    VONAGE_API_SECRET=YOUR_API_SECRET_HERE
    
    # Vonage Application Credentials (Generated during Application setup)
    VONAGE_APPLICATION_ID=YOUR_APPLICATION_ID_HERE
    # Path relative to the project root where private.key is stored
    VONAGE_PRIVATE_KEY_PATH=./private.key
    
    # Vonage Number linked to the Application (Use E.164 format ideally, e.g., 14155550100)
    VONAGE_SENDER_NUMBER=YOUR_VONAGE_US_NUMBER_HERE
    
    # Optional: Server Port
    PORT=3000
    • Replace placeholder values with your actual credentials.
    • Ensure VONAGE_PRIVATE_KEY_PATH points correctly to where you saved the private.key file.
    • Use your purchased/linked Vonage US number for VONAGE_SENDER_NUMBER.

4.1. A2P 10DLC Registration (Required for US Production)

Complete 10DLC (10-Digit Long Code) registration for production A2P messaging in the US. Mandatory as of 2025 for all Application-to-Person SMS/MMS traffic over US long code numbers.

Why 10DLC Registration is Required:

  • Carrier Compliance: US mobile carriers require all A2P traffic to be registered to prevent spam and improve message deliverability.
  • Higher Throughput: Registered 10DLC numbers can send 0.25 to 240 messages per second, compared to severely throttled or blocked unregistered traffic.
  • Message Filtering: Unregistered A2P traffic may be filtered or blocked entirely by carriers.

Registration Steps:

  1. Brand Registration:

    • Navigate to "10DLC" or "Campaign Registry" in the Vonage Dashboard.
    • Register your business or organization as a Brand. You'll need:
      • Legal business name and type (LLC, Corporation, Non-Profit, etc.)
      • EIN (Employer Identification Number) or tax ID
      • Business address and contact information
      • Website URL (required for most business types)
    • Brand registration typically takes 1 – 2 business days for approval.
    • Brand Trust Score: Your brand receives a trust score that affects your campaign throughput limits.
  2. Campaign Registration:

    • After Brand approval, register one or more Campaigns for your specific use cases.
    • Select a campaign use case that matches your messaging purpose:
      • Customer Care
      • Marketing
      • Account Notifications
      • 2FA (Two-Factor Authentication)
      • Higher Education
      • Others (see Vonage documentation for full list)
    • Provide sample message content that accurately represents what you'll send.
    • Campaign registration typically takes 1 – 5 business days for approval.
  3. Link Numbers to Campaign:

    • Once your Campaign is approved, link your US long code number(s) to the Campaign in the Vonage Dashboard.
    • Only linked numbers benefit from approved throughput limits.

Throughput Limits (2025):

10DLC throughput varies based on your Brand trust score and Campaign type:

  • Low Trust Score: 0.25 – 2 messages per second
  • Standard Brands: 4.5 – 15 messages per second
  • High Trust Score: 60 – 240 messages per second (requires Brand verification and higher fees)

Fees:

  • Brand Registration: One-time fee ($4) plus annual renewal ($1.50)
  • Campaign Registration: One-time fee (~$15 per campaign)
  • Carrier Pass-Through Fees: Monthly per-number fees (~$1.50 – $8.00 depending on carrier)

Compliance Guidelines:

  • Obtain proper opt-in consent before sending messages
  • Include opt-out instructions in messages (at least monthly)
  • Use your registered Brand name in messages
  • Send only message content that matches your registered Campaign use case
  • Follow CTIA Messaging Principles and Best Practices

References:


5. Implement Error Handling and Logging

We've already incorporated basic error handling, but let's refine and discuss logging.

  1. Error Handling Strategy:

    • Input Validation: Handle invalid client requests early (in the API route handler) with 400 Bad Request responses.
    • Vonage API Errors: Catch errors during messagesClient.send call within sendMmsMessage function. Log detailed errors server-side. Respond to client with generic 500 Internal Server Error to avoid leaking internal details.
    • Configuration Errors: Check for missing environment variables on startup and exit gracefully.
  2. Logging:

    • Current Logging: We use console.log for informational messages (request received, MMS initiated) and console.error for errors (validation failures, Vonage API errors).
    • Production Logging: For production, replace console.log/console.error with a dedicated logging library like Winston or Pino. These offer features like:
      • Log levels (debug, info, warn, error)
      • Structured logging (JSON format for easier parsing)
      • Multiple transports (writing logs to files, databases, or logging services)
      • Log rotation
    • Example (Conceptual with Winston):
      javascript
      // // Conceptual Winston Setup (replace console logs)
      // const winston = require('winston');
      // const logger = winston.createLogger({
      //   level: 'info', // Log info and above
      //   format: winston.format.json(), // Log in JSON format
      //   transports: [
      //     new winston.transports.Console(), // Log to console
      //     // new winston.transports.File({ filename: 'error.log', level: 'error' }), // Log errors to file
      //     // new winston.transports.File({ filename: 'combined.log' }) // Log all levels to another file
      //   ],
      // });
      //
      // // Replace console.log('Info message') with logger.info('Info message');
      // // Replace console.error('Error message', error) with logger.error('Error message', { error: error.message });
  3. Retry Mechanisms: The Vonage platform itself often has retry mechanisms for webhooks. For sending messages, if a send operation fails due to transient network issue or temporary Vonage outage (e.g., 5xx errors from Vonage), you could implement a retry strategy with exponential backoff in your sendMmsMessage function. However, for sending single transactional MMS, retrying immediately might not always be desirable (could lead to duplicate sends if the first request actually succeeded but the response failed). A more robust approach often involves queuing failed messages for later retry attempts or manual intervention, which is beyond the scope of this basic guide.


6. Database Schema and Data Layer

For this specific application (simply sending MMS via an API call), a database is not required. We are not storing message history, user data, or application state beyond the configuration in .env.

If you were building a more complex application (e.g., tracking sent messages, managing contacts, queuing messages), you would introduce a database (like PostgreSQL, MongoDB) and a data access layer (using an ORM like Prisma or Sequelize, or native drivers). This would involve:

  • Defining schemas/models (e.g., a Messages table with recipient, status, message_uuid, sent_at, etc.)
  • Implementing functions to interact with the database (create, read, update records)
  • Setting up database migrations

7. Add Security Features

Security is paramount when handling API keys and sending messages.

  1. Input Validation and Sanitization:

    • We implemented basic validation for required fields (recipient, imageUrl), URL format, and phone number format in the /send-mms route.
    • Enhancement: Use libraries like joi or express-validator for more robust and declarative validation schemas.
    • Sanitization: While less critical for the fields used here (phone number, URL), always sanitize user input intended for display or database storage to prevent Cross-Site Scripting (XSS) attacks. Libraries like express-validator often include sanitization methods.
  2. Secure Credential Handling:

    • .env File: We use .env to keep credentials out of code.
    • .gitignore: Ensure .env and private.key are listed in .gitignore.
    • Production: Use environment variables provided by your deployment platform (e.g., Heroku Config Vars, AWS Secrets Manager, Docker environment variables) instead of committing a .env file. Load private.key content securely, potentially directly into an environment variable or from a secure file mount.
  3. Protection Against Common Vulnerabilities:

    • Rate Limiting: Prevent abuse by limiting the number of requests a client can make to your /send-mms endpoint within a given time window. Use middleware like express-rate-limit.
      bash
      npm install express-rate-limit
      javascript
      // // Example Rate Limiting (add before your routes in index.js)
      // const rateLimit = require('express-rate-limit');
      // const limiter = rateLimit({
      //  windowMs: 15 * 60 * 1000, // 15 minutes
      //  max: 100, // Limit each IP to 100 requests per windowMs
      //  message: 'Too many requests from this IP. Try again after 15 minutes.'
      // });
      // app.use('/send-mms', limiter); // Apply limiter specifically to the send endpoint
    • Helmet: Use helmet middleware to set various HTTP headers that improve security (e.g., X-Content-Type-Options, Referrer-Policy, Strict-Transport-Security).
      bash
      npm install helmet
      javascript
      // // Example Helmet Usage (add near the top of middleware in index.js)
      // const helmet = require('helmet');
      // app.use(helmet());
  4. Authentication/Authorization (API Layer):

    • Our current API is open. In a real-world scenario, protect the /send-mms endpoint. Common methods include:
      • API Key: Require clients to send a secret API key in a header (e.g., X-API-Key). Validate this key on the server.
      • JWT (JSON Web Tokens): Implement user authentication, issue JWTs upon login, and require valid JWTs for API access.

8. Handle Special Cases

  • Image URL Requirements: The imageUrl must be publicly accessible without requiring authentication. Vonage servers need to fetch this image to send it. Ensure the URL points directly to the image file (.jpg, .jpeg, .png). Redirects might cause issues.
  • US Number Restrictions: Vonage MMS via Messages API generally works for sending from US 10DLC, Toll-Free, or Short Code numbers to US destination numbers. Sending to international numbers or using non-US Vonage numbers for MMS via this API might not be supported or may require different configurations. Always check the latest Vonage documentation for number capabilities.
  • A2P Use Case: MMS is intended for Application-to-Person communication. Using Vonage virtual numbers to send MMS to other Vonage virtual numbers might not work reliably or might be blocked.
  • Character Limits: While MMS supports longer text captions than SMS, there are still practical limits. Keep captions reasonably concise.
  • Encoding: Ensure your Node.js environment and Express app handle UTF-8 encoding correctly, especially when dealing with captions containing special characters. Express generally handles this well by default.

9. Implement Performance Optimizations

For this simple sending API, performance bottlenecks are unlikely unless sending extremely high volumes concurrently.

  • SDK Efficiency: The Vonage Node.js SDK is generally efficient.
  • Asynchronous Operations: Using async/await ensures Node.js isn't blocked while waiting for Vonage API response.
  • Connection Pooling: The underlying HTTP requests made by the SDK typically benefit from Node.js's default connection pooling.
  • Caching: Caching is not applicable here, as each API call represents a unique send request.
  • Load Testing: If high throughput is expected, use tools like k6, Artillery, or ApacheBench (ab) to load test the /send-mms endpoint and identify potential bottlenecks in your infrastructure or rate limiting by Vonage.
  • Profiling: Use Node.js built-in profiler (node --prof index.js) or tools like Clinic.js to analyze CPU usage and event loop delays under load if performance issues arise.

10. Add Monitoring, Observability, and Analytics

  • Health Checks: The / endpoint provides a basic health check. Monitoring services (like UptimeRobot, Pingdom, or Kubernetes liveness probes) can ping this endpoint to ensure the service is running.
  • Logging: As discussed in Section 5, robust logging (preferably structured JSON) is key. Forward logs to a centralized logging platform (e.g., Datadog, Splunk, ELK stack) for analysis and alerting.
  • Error Tracking: Integrate services like Sentry or Bugsnag to automatically capture, aggregate, and alert on unhandled exceptions and errors within your application.
  • Vonage Dashboard: Monitor message status, usage, and potential delivery errors directly within the Vonage API Dashboard under "Logs" > "Messages API Logs". Filter by Application ID or Message UUID.
  • Metrics: Instrument your application to send metrics (e.g., request count, error rate, response latency for /send-mms, MMS success/failure count) to a monitoring system like Prometheus (with Grafana for dashboards) or Datadog.

11. Troubleshoot Common MMS Errors with Vonage

  • 401 Unauthorized Error:
    • Cause: Incorrect credentials or authentication method. For Messages API v1 (MMS), ensure you initialize the Vonage client with applicationId and privateKey. Double-check VONAGE_APPLICATION_ID and the path VONAGE_PRIVATE_KEY_PATH in .env. Verify private.key file content is correct and hasn't been corrupted. Ensure the number VONAGE_SENDER_NUMBER is correctly linked to VONAGE_APPLICATION_ID in the dashboard.
    • Solution: Verify all credentials and the path. Ensure the number is linked. Confirm MMS capability is enabled on your account/number if necessary (contact Vonage support).
  • Non-Whitelisted Destination Error (During Testing/Trial):
    • Cause: Vonage trial accounts can typically only send messages to phone numbers verified and whitelisted in your account dashboard. This is a security measure to prevent abuse during the trial period.
    • Solution: Log into the Vonage Dashboard, navigate to "Settings" or "Numbers" section, and add the destination phone number to your verified numbers list. Alternatively, upgrade to a paid account to remove this restriction.
  • Missing or Invalid Image URL Error:
    • Cause: The image URL provided is not accessible, returns a 404 error, requires authentication, or points to an unsupported file format.
    • Solution: Verify the image URL is publicly accessible by testing it in a browser. Ensure it returns a valid image file (.jpg, .jpeg, or .png). Check that the URL uses HTTPS and does not require authentication headers.
  • 10DLC Registration Required Error (Production US Messaging):
    • Cause: As of 2025, all A2P SMS/MMS traffic over US long code numbers requires completed 10DLC Brand and Campaign registration. Messages sent without proper registration may be blocked by carriers.
    • Solution: Complete 10DLC Brand registration and Campaign registration through the Vonage Dashboard. This process typically takes 1 – 5 business days for approval. See the Vonage 10DLC documentation for detailed registration steps.
  • Message Delivery Delays or Failures:
    • Cause: Network issues, carrier filtering, recipient phone issues, or Vonage service disruptions.
    • Solution: Check the Vonage Dashboard under "Logs" > "Messages API Logs" for delivery status and error details. Monitor the message_uuid for status updates. Implement webhook handlers to receive real-time delivery status notifications.
  • Rate Limit Exceeded Error:
    • Cause: Sending too many messages too quickly. Vonage enforces rate limits based on your account type and 10DLC campaign registration tier.
    • Solution: Implement exponential backoff retry logic. For 10DLC numbers, throughput limits range from 0.25 to 240 messages per second depending on your brand trust score and campaign type. Check your specific limits in the Vonage Dashboard.

Important Caveats:

  • MMS Availability: MMS via Vonage Messages API is primarily supported for US-to-US messaging. International MMS support is limited and varies by destination country and carrier.
  • Image Size Limits: While not explicitly documented in Messages API v1, carriers typically enforce MMS message size limits (often 300KB – 600KB total). Use optimized, compressed images to ensure reliable delivery.
  • Messages API Version: This guide uses Messages API v1, currently required for MMS support. Be aware that Vonage may release newer API versions with different authentication methods or payload structures.
  • SDK Compatibility: This guide uses @vonage/server-sdk version 3.x (latest as of 2025: 3.24.1). Always check the official Vonage SDK changelog for breaking changes when upgrading versions.

12. Deployment and CI/CD

For production deployment, consider the following:

  • Environment Variables: Use environment variable management tools (e.g., Heroku Config Vars, AWS Systems Manager Parameter Store, Docker environment variables) to securely manage credentials and configuration.
  • Security Best Practices: Follow security best practices for your deployment platform. Use HTTPS, secure credential handling, and implement rate limiting and authentication.
  • Monitoring and Logging: Set up monitoring and logging for your deployed application. Use a centralized logging platform and integrate with monitoring tools for real-time visibility.
  • CI/CD Pipelines: Implement CI/CD pipelines for automated testing, building, and deployment. Use tools like GitHub Actions, Jenkins, or CircleCI.