code examples
code examples
Send MMS with Node.js, Express, and Vonage
A step-by-step guide to building a Node.js/Express API for sending MMS messages using the Vonage Messages API, covering setup, implementation, security, and deployment.
Send MMS with Node.js, Express, and Vonage
This guide provides a step-by-step walkthrough for building a Node.js application using the Express framework to send Multimedia Messaging Service (MMS) messages via the Vonage Messages API. We'll cover everything from project setup and core implementation to security, error handling, and deployment considerations.
By the end of this tutorial, you will have a functional API endpoint capable of accepting requests and sending MMS messages, including images, to specified recipients using your Vonage account. This solves the common need for applications to programmatically send rich media content to users' mobile devices within the US.
Project Overview and Goals
- Goal: Create a simple REST API endpoint using Node.js and Express that sends an MMS message (text + image) via the Vonage Messages API.
- Problem Solved: Enables applications to programmatically send images and text via MMS to US phone numbers, useful for notifications, alerts, marketing, or user engagement.
- Technologies:
- Node.js: A JavaScript runtime environment for server-side development.
- Express: A minimal and flexible Node.js web application framework for building APIs.
- Vonage Messages API: A unified API from Vonage for sending messages across various channels, including MMS.
- @vonage/server-sdk: The official Vonage Node.js SDK, simplifying interaction with Vonage APIs.
- dotenv: A module to load environment variables from a
.envfile.
- Prerequisites:
- A Vonage API account (Sign up here).
- Your Vonage API Key and API Secret (found on your Vonage Dashboard).
- Node.js and npm (or yarn) installed locally.
- A US-based Vonage phone number capable of sending SMS & MMS (How to buy a number).
- A publicly accessible URL for the image you want to send (e.g., hosted on a CDN or public server). Supported formats: JPG, JPEG, PNG.
- (Optional but recommended) ngrok or a similar tool to expose your local server for testing webhooks, though not strictly required for just sending MMS.
- Basic familiarity with JavaScript and REST APIs.
System Architecture
The basic flow involves your client application making an HTTP POST request to your Node.js/Express API. The API validates the request, uses the Vonage SDK (authenticated with your credentials) to call the Vonage Messages API, which then sends the MMS message to the recipient's phone.
+-----------------+ +-------------------------+ +------------------+ +-----------------+
| Client App |----->| Node.js/Express API |----->| Vonage Messages |----->| Recipient Phone |
| (e.g., Web/Mobile)| POST /send-mms | (using SDK + Credentials)| API | (Receives MMS) |
+-----------------+ +-------------------------+ +------------------+ +-----------------+
| - Validate Request |
| - Construct MMS Payload |
| - Call Vonage SDK |
+-------------------------+1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies.
-
Create Project Directory: Open your terminal and create a new directory for your project, then navigate into it.
bashmkdir vonage-mms-sender cd vonage-mms-sender -
Initialize npm: Initialize a new Node.js project. The
-yflag accepts default settings.bashnpm init -y -
Install Dependencies: Install Express for the web server, the Vonage Server SDK, and
dotenvfor managing environment variables.bashnpm install express @vonage/server-sdk dotenv -
Create Project Structure: Create the main application file and a file for environment variables.
bashtouch server.js .env .gitignoreYour basic structure should look like this:
textvonage-mms-sender/ ├── node_modules/ ├── .env ├── .gitignore ├── package.json ├── package-lock.json └── server.js -
Configure
.gitignore: Addnode_modulesand.envto your.gitignorefile to avoid committing sensitive credentials and dependencies.Codenode_modules .env -
Set up Environment Variables (
.env): Open the.envfile and add placeholders for your Vonage credentials and configuration. We will fill these in later during the Vonage configuration step.dotenv# .env # Vonage API Credentials (Get from main Vonage Dashboard homepage) VONAGE_API_KEY=YOUR_VONAGE_API_KEY VONAGE_API_SECRET=YOUR_VONAGE_API_SECRET # Vonage Application Credentials (Get from Dashboard > Applications > Your Application) VONAGE_APPLICATION_ID=YOUR_VONAGE_APPLICATION_ID VONAGE_PRIVATE_KEY_PATH=./private.key # Path relative to project root # Vonage Number (Your MMS-capable US number from Vonage) VONAGE_MMS_NUMBER=YOUR_VONAGE_US_NUMBER # Server Port PORT=3000- Purpose: Using environment variables keeps sensitive data out of your codebase, making it more secure and configurable across different environments (development, staging, production).
2. Implementing Core Functionality
Now, let's write the core logic in server.js to set up the Express server and handle the MMS sending.
// server.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'); // Specifically for Messages API
// --- Input Validation ---
// Basic check function (can be expanded with libraries like Joi or express-validator)
function validateInput(body) {
const { to, imageUrl, caption } = body;
if (!to || !imageUrl || !caption) {
return 'Missing required fields: to, imageUrl, caption';
}
// Add more specific validation (e.g., phone number format, URL format) here
if (!/^https?:\/\/.+\.(jpg|jpeg|png)$/i.test(imageUrl)) {
return 'Invalid or unsupported image URL format. Must be HTTP/HTTPS JPG, JPEG, or PNG.';
}
// Basic E.164 format validation isn't strictly done here anymore,
// but you could add a regex check if needed, returning an error message.
// The warning about non-E.164 is handled in the route logic now.
// Example: if (!/^\+?[1-9]\d{1,14}$/.test(to)) { return 'Invalid phone number format'; }
return null; // No errors
}
// --- Vonage Client Initialization ---
// Ensure all required environment variables are present
const requiredEnvVars = [
'VONAGE_API_KEY',
'VONAGE_API_SECRET',
'VONAGE_APPLICATION_ID',
'VONAGE_PRIVATE_KEY_PATH',
'VONAGE_MMS_NUMBER'
];
const missingEnvVars = requiredEnvVars.filter(varName => !process.env[varName]);
if (missingEnvVars.length > 0) {
console.error(`ERROR: Missing required environment variables: ${missingEnvVars.join(', ')}`);
console.error(""Please check your .env file or environment configuration."");
process.exit(1); // Exit if configuration is incomplete
}
let vonageMessages;
try {
// Use the specific Messages client from the SDK
vonageMessages = new Messages({
apiKey: process.env.VONAGE_API_KEY,
apiSecret: process.env.VONAGE_API_SECRET,
applicationId: process.env.VONAGE_APPLICATION_ID,
privateKey: process.env.VONAGE_PRIVATE_KEY_PATH // Path to your private key file
});
} catch (error) {
console.error(""ERROR: Failed to initialize Vonage Messages client."", error.message);
console.error(""Check Vonage credentials and private key path in .env file."");
if (error.code === 'ENOENT') {
console.error(`Ensure the private key file exists at: ${process.env.VONAGE_PRIVATE_KEY_PATH}`);
}
process.exit(1);
}
// --- Express App Setup ---
const app = express();
app.use(express.json()); // Middleware to parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Middleware to parse URL-encoded bodies
const PORT = process.env.PORT || 3000;
// --- Health Check Route ---
app.get('/health', (req, res) => {
res.status(200).json({ status: 'OK', timestamp: new Date().toISOString() });
});
// --- MMS Sending Route ---
app.post('/send-mms', async (req, res) => {
// 1. Validate Input
const validationError = validateInput(req.body);
if (validationError) {
console.warn('Validation Error:', validationError, 'Request Body:', req.body);
return res.status(400).json({ success: false, message: validationError });
}
const { to, imageUrl, caption } = req.body;
const from = process.env.VONAGE_MMS_NUMBER; // Use the number from .env
// Ensure 'to' number is in E.164 format (Vonage prefers this)
// Basic example: remove non-digits, add +1 if needed for US
let formattedTo = to.replace(/\D/g, '');
if (formattedTo.length === 10) {
formattedTo = `+1${formattedTo}`;
} else if (formattedTo.length === 11 && formattedTo.startsWith('1')) {
formattedTo = `+${formattedTo}`;
} else if (!formattedTo.startsWith('+')) {
// If it's not clearly US/Canada or already E.164, log a warning but proceed
console.warn(""Attempting to send to potentially non-E.164 number:"", formattedTo, ""(Original input:"", to, "")"");
// For robustness, you might want stricter validation or prefixing rules
// depending on your target regions. MMS outside US/Canada via Vonage
// has varying support and different number requirements.
}
// 2. Construct MMS Payload using Vonage SDK helpers
const mmsPayload = {
message_type: 'image', // Specify message type as image for MMS
to: formattedTo,
from: from,
channel: 'mms', // Specify MMS channel
image: {
url: imageUrl,
caption: caption
}
// client_ref: 'your-internal-reference-123' // Optional: For tracking
};
// 3. Send MMS via Vonage
try {
console.log(`Attempting to send MMS to ${formattedTo} from ${from}`);
const response = await vonageMessages.send(mmsPayload);
console.log('Vonage API Response:', response);
// Success: Vonage accepted the message for delivery
res.status(202).json({ // 202 Accepted is appropriate as delivery is async
success: true,
message: 'MMS submitted successfully.',
message_uuid: response.message_uuid
});
} catch (error) {
// Handle Vonage API errors
console.error('Vonage API Error:', error);
let statusCode = 500; // Internal Server Error by default
let errorMessage = 'Failed to send MMS due to an internal error.';
if (error.response) {
// Error response from Vonage API
statusCode = error.response.status || 500;
errorMessage = `Vonage API Error (${statusCode}): ${error.response.data?.title || error.message}`;
if(error.response.data?.detail) errorMessage += ` Details: ${error.response.data.detail}`;
if(error.response.data?.invalid_parameters) {
errorMessage += ` Invalid Parameters: ${JSON.stringify(error.response.data.invalid_parameters)}`;
}
} else if (error.request) {
// Request made but no response received (network issue, Vonage down?)
statusCode = 504; // Gateway Timeout
errorMessage = 'No response received from Vonage API.';
} else {
// Setup error or other unexpected issue
errorMessage = `Failed to send MMS: ${error.message}`;
}
// Specific error handling checks (based on common Vonage errors)
if (errorMessage.includes('Non-Whitelisted Destination') || (error.response?.data?.type?.includes('AUTHENTICATION_FAILED') && errorMessage.includes('demo mode'))) {
statusCode = 403; // Forbidden
errorMessage = ""Destination number not whitelisted for trial account, or authentication issue related to trial status. Add the number to your test numbers in the Vonage dashboard."";
console.error(""TRIAL ACCOUNT RESTRICTION: Ensure the recipient number is added to your allowed test numbers on the Vonage dashboard."");
} else if (statusCode === 401 || errorMessage.includes('Authentication failed')) {
statusCode = 401; // Unauthorized
errorMessage = ""Authentication failed. Check Vonage API Key, Secret, Application ID, and Private Key configuration."";
} else if (statusCode === 403) {
// Could be other authorization issues like number not linked or capability missing
errorMessage += "" Check if the 'from' number is linked to the Application ID and has MMS capabilities enabled."";
} else if (errorMessage.includes('Invalid Parameters') || statusCode === 400) {
statusCode = 400; // Bad Request
// Error message often contains details
}
res.status(statusCode).json({
success: false,
message: errorMessage,
// Optionally include error details in non-production environments
// errorDetails: process.env.NODE_ENV !== 'production' ? error : undefined
});
}
});
// --- Start Server ---
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log(`API Endpoint available at POST /send-mms`);
console.log(`Using Vonage Number: ${process.env.VONAGE_MMS_NUMBER}`);
console.log(`Make sure the image URL provided in requests is publicly accessible.`);
console.log(`Ensure your Vonage account/number is set up for US MMS.`);
});
// Export the app instance for testing purposes
module.exports = app;- Why this approach?
- We use
dotenvto manage credentials securely. - We import the specific
Messagesclient from@vonage/server-sdkas recommended for the Messages API. - Basic input validation is included to catch common errors early.
- The code attempts basic E.164 formatting for the destination number, logging a warning if the input format is ambiguous.
- The
vonageMessages.send()method is asynchronous, so we useasync/await. - Comprehensive error handling distinguishes between validation errors, Vonage API errors, and network issues, providing informative feedback. Specific checks for common issues like trial account restrictions are included.
- We return a
202 Acceptedstatus on successful submission, acknowledging the asynchronous nature of message delivery. - The Express
appis exported to allow for integration testing with tools likesupertest.
- We use
3. Building the API Layer
The server.js file already defines our API endpoint: POST /send-mms.
-
Authentication/Authorization: This simple example doesn't include explicit API authentication (like API keys or JWT for your API). In a production scenario, you would secure this endpoint using middleware (e.g.,
express-bearer-token, Passport.js) to ensure only authorized clients can trigger MMS sends. -
Request Validation: Basic validation is implemented in the
validateInputfunction. For production, consider more robust libraries likeJoiorexpress-validatorfor complex validation rules. -
API Endpoint Documentation:
- Endpoint:
POST /send-mms - Content-Type:
application/json - Request Body (JSON):
json
{ ""to"": ""+15551234567"", ""imageUrl"": ""https://placekitten.com/200/300"", ""caption"": ""Hello from Vonage MMS!"" } - Success Response (202 Accepted):
json
{ ""success"": true, ""message"": ""MMS submitted successfully."", ""message_uuid"": ""aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"" } - Error Response (e.g., 400 Bad Request, 401 Unauthorized, 403 Forbidden, 500 Internal Server Error):
json
{ ""success"": false, ""message"": ""Descriptive error message (e.g., Missing required fields, Authentication failed, Non-Whitelisted Destination, etc.)"" }
- Endpoint:
-
Testing with
curl: Replace placeholders with your actual recipient number and a valid image URL.bashcurl -X POST http://localhost:3000/send-mms \ -H ""Content-Type: application/json"" \ -d '{ ""to"": ""+15551234567"", ""imageUrl"": ""https://www.vonage.com/content/dam/vonage/us-en/logos/vbc/vonage_logo_retina.png"", ""caption"": ""Testing Vonage MMS API"" }' -
Testing with Postman:
- Create a new request.
- Set the method to
POST. - Set the URL to
http://localhost:3000/send-mms. - Go to the ""Body"" tab, select ""raw"", and choose ""JSON"" from the dropdown.
- Paste the JSON request body (like the one in the
curlexample). - Click ""Send"".
4. Integrating with Vonage (Dashboard Setup)
This is a critical step to get the necessary credentials for your .env file.
- Log in to Vonage: Go to your Vonage API Dashboard.
- Get API Key and Secret: Your
VONAGE_API_KEYandVONAGE_API_SECRETare displayed prominently at the top of the dashboard homepage. Copy these into your.envfile. - Create a Vonage Application:
- Navigate to ""Applications"" > ""Create a new application"".
- Give your application a name (e.g., ""Node MMS Sender"").
- Click ""Generate public and private key"". This will automatically download the
private.keyfile. Save this file in the root directory of your Node.js project (or updateVONAGE_PRIVATE_KEY_PATHin.envif you save it elsewhere). The public key is automatically stored by Vonage. - Enable the ""Messages"" capability.
- You need to provide Status URL and Inbound URL webhooks. For sending MMS, these primarily receive delivery status updates or inbound replies. If you don't need to process these immediately, you can use a placeholder service:
- Go to MockBin.
- Click ""Create Bin"". Leave defaults (200 OK) and click ""Create Bin"".
- Copy the generated Mockbin URL (e.g.,
https://mockbin.org/bin/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). - Paste this URL into both the ""Status URL"" and ""Inbound URL"" fields in the Vonage application settings. Crucially, ensure the URL ends before any
/viewpath. - (Self-correction based on research): The research mentions using ngrok here. While MockBin works for just sending, if you plan to receive delivery receipts or replies later, you'll need a real endpoint exposed via ngrok or a deployed server. For now, MockBin is sufficient if you only care about sending.
- Click ""Generate new application"".
- On the next screen, copy the generated Application ID. This is your
VONAGE_APPLICATION_ID. Paste it into your.envfile.
- Link Your Vonage Number:
- While still on the application details page, scroll down to ""Link virtual numbers"".
- Find your US MMS-capable number in the list and click the ""Link"" button next to it. If you don't have one, you'll need to purchase one via the ""Numbers"" section first. This connects incoming messages/status updates for that number to this application's webhooks. It also authorizes this application (using the Application ID and Private Key) to send messages from this number.
- Verify SMS Settings (Optional but Recommended):
- Go to ""Account"" > ""API settings"".
- Scroll down to ""SMS Settings"".
- Ensure ""Default SMS Setting"" is set to Messages API. This ensures consistency if you also send SMS using this application. Click ""Save changes"" if you modify it.
- Fill
.env: Ensure allVONAGE_variables in your.envfile are now filled with the correct values obtained from the dashboard and yourprivate.keyfile path. Remember to add your purchased US MMS number asVONAGE_MMS_NUMBER.
5. Error Handling, Logging, and Retry Mechanisms
- Error Handling: The
server.jscode includestry...catchblocks around the Vonage API call and specific checks for common errors (validation, authentication, trial limits, API issues, network problems). It returns appropriate HTTP status codes and informative JSON error messages. - Logging: Basic
console.log,console.warn, andconsole.errorare used. For production, integrate a more robust logging library likewinstonorpino. These enable structured logging (e.g., JSON format), different log levels (debug, info, warn, error), and outputting logs to files or external services (like Datadog, Logstash).bash# Example: Adding Winston npm install winstonjavascript// Example winston setup (add near top of server.js) const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ new winston.transports.Console(), // Add file transport for production // new winston.transports.File({ filename: 'error.log', level: 'error' }), // new winston.transports.File({ filename: 'combined.log' }), ], }); // Replace console.log/warn/error with logger.info/warn/error // e.g., logger.info('Server running...'); logger.error('Vonage API Error:', error); - Retry Mechanisms: Sending an MMS is generally idempotent on the Vonage side if you use the same parameters. However, temporary network issues or Vonage service fluctuations might cause the API call from your server to Vonage to fail.
- Client-Side: The client calling your
/send-mmsendpoint could implement retries with exponential backoff if they receive a 5xx error. - Server-Side: You could wrap the
vonageMessages.send()call in a retry loop (using libraries likeasync-retry) for specific error conditions (like 503 Service Unavailable or 504 Gateway Timeout from Vonage). Be cautious not to retry on 4xx errors (like invalid input or authentication failure) as these will likely fail repeatedly. - Vonage Internal Retries: Vonage itself has internal mechanisms to retry delivering the message to the carrier/handset if temporary issues occur downstream.
- Client-Side: The client calling your
6. Database Schema and Data Layer (Optional)
For this specific guide focused on sending, a database isn't strictly required. However, in a real-world application, you would likely want to track sent messages, their status, and associated metadata.
- Schema Idea (e.g., using PostgreSQL):
sql
CREATE TABLE mms_log ( id SERIAL PRIMARY KEY, message_uuid UUID UNIQUE, -- Vonage message ID (received on successful send) recipient_number VARCHAR(20) NOT NULL, sender_number VARCHAR(20) NOT NULL, image_url TEXT NOT NULL, caption TEXT, status VARCHAR(50) DEFAULT 'submitted', -- e.g., submitted, delivered, failed, rejected submitted_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, last_updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, vonage_status_code VARCHAR(10), -- From status webhook error_message TEXT, -- From status webhook or initial send failure client_ref VARCHAR(100) -- Optional internal tracking reference ); CREATE INDEX idx_mms_log_message_uuid ON mms_log(message_uuid); CREATE INDEX idx_mms_log_recipient ON mms_log(recipient_number); CREATE INDEX idx_mms_log_status ON mms_log(status); CREATE INDEX idx_mms_log_submitted_at ON mms_log(submitted_at); - Implementation: Use an ORM like Prisma or Sequelize, or a query builder like Knex.js to interact with the database. You would insert a record when the message is submitted (
202 Acceptedfrom Vonage) and update the status based on delivery receipts received via the Status Webhook (which would require implementing an endpoint for the Status URL configured in the Vonage Application).
7. Security Features
- Input Validation & Sanitization:
- The
validateInputfunction performs basic checks. Use robust libraries (Joi,express-validator) to strictly define expected data types, formats (E.164 for numbers, valid URL), and lengths. - Sanitize any input that might be reflected in logs or potentially other outputs, though in this case, inputs are primarily passed to Vonage. Vonage handles sanitization on their end before delivery.
- The
- Environment Variables: Keep
.envout of Git (.gitignore). Use platform-specific secret management in production (e.g., AWS Secrets Manager, HashiCorp Vault, Doppler). - Secure API Endpoint: Protect the
/send-mmsendpoint with authentication/authorization (API keys, JWT, OAuth) to prevent unauthorized use. - Rate Limiting: Implement rate limiting (e.g., using
express-rate-limit) on the/send-mmsendpoint to prevent abuse and protect your Vonage account balance/rate limits.bashnpm install express-rate-limitjavascript// Add near other middleware in server.js const rateLimit = require('express-rate-limit'); const apiLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per windowMs message: 'Too many requests from this IP, please try again after 15 minutes' }); app.use('/send-mms', apiLimiter); // Apply limiter specifically to the send endpoint - HTTPS: Always run your Node.js application behind a reverse proxy (like Nginx or Caddy) that handles TLS/SSL termination in production, ensuring traffic is encrypted.
- Dependency Security: Regularly audit dependencies for known vulnerabilities (
npm audit) and update them.
8. Handling Special Cases
- MMS Limitations:
- Geography: Vonage MMS via the Messages API is primarily for A2P (Application-to-Person) use cases within the United States. Sending MMS internationally or P2P (Person-to-Person) via virtual numbers has limited or no support.
- File Types: Only
.jpg,.jpeg, and.pngimage formats are reliably supported. - Image URL: The
imageUrlmust be publicly accessible over HTTP/HTTPS. Vonage servers need to fetch the image. Private or localhost URLs will not work. - Number Types: Sending from Toll-Free, 10DLC, or Short Codes is generally supported within the US, but capabilities might vary. Sending to virtual numbers is not supported by the Messages API for MMS.
- Character Limits: While MMS itself supports longer text, carrier limitations might exist. Keep captions reasonably concise.
- Idempotency: If you need to ensure a message isn't sent multiple times due to retries, you could generate a unique
client_refon your side, store it (e.g., in the database), and potentially check if a message with thatclient_refwas recently submitted before sending again. However, relying on themessage_uuidreturned by Vonage is usually sufficient for tracking.
9. Performance Optimizations
- Asynchronous Operations: Node.js and the Vonage SDK are inherently asynchronous. The
async/awaitpattern ensures your server isn't blocked while waiting for Vonage's response. - Payload Size: Image size affects fetch time by Vonage and delivery time/cost. Optimize images before hosting them.
- Connection Pooling: The Vonage SDK handles underlying HTTP connections. For very high throughput, ensure your Node.js process has sufficient resources.
- Caching: Caching is less relevant for the send operation itself, but if you were fetching data to construct the MMS, caching that data could improve performance.
- Load Balancing: For high availability and throughput, run multiple instances of your Node.js application behind a load balancer (e.g., Nginx, AWS ELB). Ensure sessions are handled appropriately if you add authentication that requires session state (or use stateless methods like JWT).
10. Monitoring, Observability, and Analytics
- Health Checks: The
/healthendpoint provides a basic check. Expand it to verify database connectivity or other critical dependencies if added. - Metrics: Track key metrics:
- Request rate to
/send-mms. - Request latency.
- Rate of successful submissions (202 responses).
- Rate of errors (4xx, 5xx), possibly broken down by error type.
- Use libraries like
prom-clientfor Prometheus metrics or integrate with APM solutions (Datadog, New Relic).
- Request rate to
- Logging: As mentioned, structured logging enables easier analysis and alerting (e.g., setting up alerts in your logging platform for high error rates).
- Error Tracking: Use services like Sentry or Bugsnag to capture, aggregate, and get notified about runtime errors in your application.
- Vonage Dashboard: Monitor your message logs, usage, and balance directly within the Vonage API Dashboard (""Messages API Logs"", ""Usage"", ""Billing""). This provides visibility into successful deliveries and failures reported by carriers, which occur after your API call returns
202 Accepted.
11. Troubleshooting and Caveats
Authentication failed/ 401 Unauthorized: Double-checkVONAGE_API_KEY,VONAGE_API_SECRET,VONAGE_APPLICATION_ID, andVONAGE_PRIVATE_KEY_PATHin your.envfile. Ensure the private key file exists at the specified path and is readable by the Node.js process.Non-Whitelisted Destination/ 403 Forbidden: If using a trial account, you must add the recipient's phone number to your list of approved test numbers in the Vonage Dashboard under ""Account"" > ""Test numbers"".Cannot find module './private.key'orENOENTerror: Ensure theVONAGE_PRIVATE_KEY_PATHin.envcorrectly points to the location of yourprivate.keyfile relative to where you runnode server.js. Make sure the file was downloaded correctly and hasn't been corrupted.The requested capability is not enabled for this Application/ 403 Forbidden: Ensure the ""Messages"" capability is enabled for theVONAGE_APPLICATION_IDyou are using in the Vonage Dashboard.The From number XXXXX is not associated with your Application/ 403 Forbidden: Ensure theVONAGE_MMS_NUMBERyou are sending from is linked to theVONAGE_APPLICATION_IDin the Vonage Dashboard.Invalid Parameters/ 400 Bad Request: Check the format of thetonumber (E.164 preferred), theimageUrl(must be public, valid HTTP/HTTPS URL, correct file type), and other payload parameters against the Vonage Messages API documentation. The error response often contains details about which parameter is invalid.- Message Not Received, but API Returned Success (202):
- Check the Messages API Logs in the Vonage Dashboard for the specific
message_uuid. Look for status updates likedelivered,failed, orrejected. - Verify the recipient number is correct and can receive MMS.
- Ensure the image URL is valid and remained publicly accessible after sending.
- Carrier filtering or network issues can sometimes cause delays or failures.
- Check the Messages API Logs in the Vonage Dashboard for the specific
- MMS Works, SMS Fails (or vice-versa): Ensure the Vonage number is provisioned for both SMS and MMS capabilities and linked correctly. Check the ""Messages"" vs ""SMS"" API setting under API Settings if using both types.
- Vonage API Status: Check the Vonage Status Page for any ongoing incidents.
12. Deployment and CI/CD
- Environment Configuration: Never commit your
.envfile. Use your hosting platform's mechanism for setting environment variables (e.g., AWS Elastic Beanstalk configuration, Heroku config vars, Docker environment variables). Ensure theVONAGE_PRIVATE_KEY_PATHenvironment variable correctly points to the location where your private key file is stored in the deployment environment. Alternatively, consider loading the private key content directly from an environment variable instead of a file path for better security and flexibility in containerized environments. - Build Process: For Node.js, usually involves
npm install --production(oryarn install --production) to install only necessary dependencies. - Deployment Strategy: Choose a suitable platform (e.g., Heroku, AWS Elastic Beanstalk, Google Cloud Run, DigitalOcean App Platform, Vercel Serverless Functions). Consider containerization with Docker for consistency.
- CI/CD Pipeline: Set up a pipeline (e.g., using GitHub Actions, GitLab CI, Jenkins) to automate testing, building, and deployment whenever changes are pushed to your repository.
- Process Management: Use a process manager like
pm2in production to handle running your Node.js application, manage restarts, and monitor resource usage.
Frequently Asked Questions
How to send MMS messages with Node.js?
Use the Vonage Messages API with the @vonage/server-sdk and Express. Set up a Node.js project, install dependencies, configure your Vonage account, build the /send-mms endpoint and handle requests containing the recipient number, image URL, and caption. The API interacts with Vonage to send the MMS message.
What is Vonage Messages API used for?
The Vonage Messages API is a unified platform for sending messages through various channels including MMS. This API allows developers to programmatically send rich media content, like images and text, within the US, particularly useful for sending notifications, alerts, and marketing messages.
Why does my MMS fail to send with Vonage?
MMS failures can be due to several reasons: incorrect Vonage API credentials, the recipient's number not being whitelisted (for trial accounts), an invalid or inaccessible image URL, or issues with the 'from' number not being correctly linked in the Vonage Dashboard. Check your Vonage setup in the dashboard and verify number settings.
When should I use the Messages API?
The Vonage Messages API is ideal when your application needs to send text messages, rich media messages like MMS (within the US), or messages to other channels like WhatsApp or Viber, programmatically. This provides flexibility compared to manual sending or using separate APIs.
Can I send MMS internationally with Vonage?
Vonage's Messages API primarily supports MMS within the US. International MMS or P2P MMS via virtual numbers is not reliably supported through this API. Other solutions may be required for international use cases.
How to set up a Vonage application for MMS?
In your Vonage Dashboard, create a new application, generate public and private keys (saving the private key securely), enable the "Messages" capability, set up webhook URLs for status and inbound messages (Mockbin for initial testing), copy the Application ID, and link your MMS-capable US Vonage number to this application. Then update .env with all your vonage variables.
What image formats does Vonage MMS support?
Vonage MMS supports JPG, JPEG, and PNG image formats. The image URL provided must be publicly accessible via HTTP or HTTPS for Vonage to retrieve it. Ensure images are optimized for size to improve delivery speed and cost.
How to handle Vonage API errors?
Implement `try...catch` blocks around the `vonageMessages.send()` call in your code to handle potential errors. Check the error response for specific status codes and messages to determine the cause, such as authentication issues or invalid parameters. Log errors for debugging and monitoring.
What is the purpose of the .env file?
The `.env` file stores environment variables, such as your Vonage API credentials and configuration settings. This keeps sensitive data separate from your code, improving security and making it easier to manage settings across different environments.
How to test my Vonage MMS API endpoint?
You can use tools like `curl` or Postman to send test requests to your `/send-mms` endpoint with sample recipient numbers, image URLs, and captions. Verify that the endpoint returns a 202 Accepted status for successful submissions and that the MMS message is received by the test number.
Why use a process manager like PM2?
In a production environment, a process manager like PM2 ensures your Node.js application runs continuously, restarts automatically if it crashes, and provides tools for managing multiple processes and monitoring resource usage.
What are best practices for securing the send-mms endpoint?
Secure the `/send-mms` endpoint using authentication middleware (e.g., API keys, JWT) to prevent unauthorized access. Implement input validation to sanitize and ensure proper data formatting, and add rate limiting to protect against abuse and manage costs.
How to troubleshoot Non-Whitelisted Destination error?
The "Non-Whitelisted Destination" error usually occurs with Vonage trial accounts. Add the recipient's phone number to your allowed test numbers in the Vonage Dashboard under "Account" > "Test numbers" to resolve this issue.
What is the client_ref used for in the Vonage payload?
The `client_ref` parameter is optional and can be used for internal tracking on your side. You can generate a unique identifier and include it in the MMS payload to match it with data stored in your application's database, but relying solely on Vonage's `message_uuid` is usually sufficient for tracking purposes.
How to implement retry mechanisms with Vonage Messages API?
Handle temporary network issues or Vonage service disruptions by implementing retry mechanisms with exponential backoff on the client-side or using a library like `async-retry` on your server, specifically for 5xx errors. Avoid retrying on 4xx client errors.