code examples
code examples
How to Send MMS Messages in RedwoodJS with Plivo: Complete Tutorial
Step-by-step guide to sending MMS multimedia messages in RedwoodJS using Plivo's Node.js SDK. Includes GraphQL API setup, image sending, error handling, and production deployment.
Send MMS Messages with Plivo in RedwoodJS: Complete Integration Guide
Learn how to send MMS multimedia messages in your RedwoodJS application using Plivo's MMS API. This comprehensive guide walks through integrating the Plivo Node.js SDK to send images, GIFs, and multimedia content via RedwoodJS services and GraphQL mutations. You'll build a complete implementation with setup, error handling, testing, and deployment best practices.
By following this RedwoodJS MMS tutorial, you'll create a production-ready backend for sending multimedia messages with Plivo to US and Canada recipients. Enable richer communication for user engagement, transactional notifications, or marketing campaigns directly from your RedwoodJS application.
Last Updated: October 5, 2025
What You'll Build: RedwoodJS MMS Messaging System
Goal: Implement MMS messaging functionality in a RedwoodJS application using the Plivo communications platform to send multimedia messages programmatically.
Problem Solved: Standard SMS cannot effectively handle media content like images, GIFs, videos, or audio. This implementation provides a programmatic way to send rich multimedia messages directly from your RedwoodJS application backend.
Technologies Used:
- RedwoodJS: Full-stack JavaScript/TypeScript framework leveraging services and GraphQL for clean API implementation.
- Plivo: Cloud communications platform with APIs for SMS, MMS, and Voice. We'll use their Node.js SDK.
- Node.js: Runtime environment for the RedwoodJS API side.
- Yarn: Package manager used by RedwoodJS.
- GraphQL: API query language, standard in RedwoodJS architecture.
System Architecture:
[Client (Web/Mobile)] <--(GraphQL Request)--> [RedwoodJS API]
|
| 1. Call Plivo Service
v
[Plivo MMS Service (`plivoMms.ts`)]
|
| 2. Use Plivo Node.js SDK
v
[Plivo API] --(MMS Delivery)--> [Recipient Mobile Device]
- The client triggers the MMS send via a GraphQL mutation to the RedwoodJS API.
- The RedwoodJS API's GraphQL resolver calls a dedicated service (
plivoMms.ts). - The
plivoMmsservice uses the Plivo Node.js SDK, configured with API credentials and sender details, to make an API request to Plivo. - Plivo handles the processing and delivery of the MMS message to the recipient's device (US/Canada only).
Prerequisites:
- Node.js (v20.x or higher required per RedwoodJS specification)
- Yarn (>=1.22.21 required per RedwoodJS specification)
- RedwoodJS CLI installed (
yarn global add redwoodjs) - A Plivo account (Sign up here)
- A Plivo phone number purchased from your Plivo account that is MMS-enabled and suitable for sending to the US/Canada. Plivo offers MMS-enabled long-code phone numbers only in the US and Canada.
- Basic familiarity with RedwoodJS concepts (services, GraphQL SDL, environment variables).
Setting Up Your RedwoodJS Project for MMS
We'll start with a fresh RedwoodJS project. If you have an existing project, adapt the steps accordingly.
-
Create RedwoodJS App: Open your terminal and run:
bashyarn create redwood-app ./redwood-plivo-mms -
Navigate to Project Directory:
bashcd redwood-plivo-mms -
Install Plivo Node.js SDK: Install the official Plivo helper library specifically into the
apiworkspace.bashyarn workspace api add plivoWhy
yarn workspace api add? RedwoodJS uses Yarn workspaces. This command ensures theplivopackage is added as a dependency only for the API side, where it's needed. -
Configure Environment Variables: Create a
.envfile in the root of your project. This file stores sensitive credentials and configuration securely, keeping them out of version control.bashtouch .envAdd the following variables to your
.envfile:dotenv# .env PLIVO_AUTH_ID=YOUR_PLIVO_AUTH_ID PLIVO_AUTH_TOKEN=YOUR_PLIVO_AUTH_TOKEN PLIVO_SENDER_ID=YOUR_PLIVO_MMS_ENABLED_NUMBER-
How to get these values:
PLIVO_AUTH_ID&PLIVO_AUTH_TOKEN: Log in to your Plivo Console. Your Auth ID and Auth Token are displayed prominently on the main dashboard overview page.PLIVO_SENDER_ID: This must be a Plivo phone number you have purchased or ported to your account. Navigate to Phone Numbers -> Your Numbers in the Plivo console.- Select a number that has MMS capability enabled (check the "Capabilities" column).
- Ensure it's a US or Canadian number if sending to the US/Canada.
- Copy the number in E.164 format (e.g.,
+14155551234).
-
Security: Ensure your
.envfile is listed in your.gitignorefile (RedwoodJS includes this by default) to prevent accidentally committing secrets. -
Note: RedwoodJS automatically loads variables from the
.envfile into the Node.jsprocess.envobject, making them accessible in your API-side code (likeprocess.env.PLIVO_AUTH_ID).
-
-
Project Structure: We will primarily work within the
apidirectory:api/src/lib/logger.ts: Redwood's built-in logger.api/src/services/: Where our Plivo MMS service will reside.api/src/graphql/: Where the GraphQL schema definition (SDL) for our mutation will live.api/src/functions/graphql.ts: The main GraphQL endpoint handler (often requires no changes for basic service/SDL usage)..env: Stores environment variables (already created).
Implementing the Plivo MMS Service in RedwoodJS
We'll create a RedwoodJS service to encapsulate the logic for sending MMS messages via Plivo.
-
Generate the Service: Use the Redwood CLI to generate the service files:
bashyarn rw g service plivoMmsThis creates:
api/src/services/plivoMms/plivoMms.ts: The service logic file.api/src/services/plivoMms/plivoMms.scenarios.ts: For seeding data during tests.api/src/services/plivoMms/plivoMms.test.ts: The unit test file.
-
Implement the
sendMmsFunction: Openapi/src/services/plivoMms/plivoMms.tsand replace its contents with the following:typescript// api/src/services/plivoMms/plivoMms.ts import * as plivo from 'plivo' import type { MessageCreateParams } from 'plivo/dist/resources/messages' // Import type for clarity import { logger } from 'src/lib/logger' interface SendMmsArgs { to: string // Recipient phone number in E.164 format mediaUrl: string // Publicly accessible URL of the media file text?: string // Optional text body } interface SendMmsResponse { success: boolean message: string messageUuid?: string | null // Plivo's identifier for the message error?: string | null } /** * Sends an MMS message using the Plivo API. * Requires PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, and PLIVO_SENDER_ID environment variables. * MMS sending is only supported to US and Canada numbers via Plivo. * * @param to - The recipient phone number in E.164 format (e.g., +15551234567). * @param mediaUrl - A *publicly accessible* URL to the media file (image, gif, etc.). * @param text - Optional text to include with the MMS. * @returns {Promise<SendMmsResponse>} - An object indicating success or failure. */ export const sendMms = async ({ to, mediaUrl, text, }: SendMmsArgs): Promise<SendMmsResponse> => { logger.info({ to, mediaUrl }, 'Attempting to send Plivo MMS') // --- Input Validation --- if (!process.env.PLIVO_AUTH_ID || !process.env.PLIVO_AUTH_TOKEN || !process.env.PLIVO_SENDER_ID) { logger.error('Plivo credentials or sender ID missing in environment variables.') return { success: false, message: 'Server configuration error: Plivo credentials missing.', error: 'Missing environment variables', } } if (!to || !mediaUrl) { logger.warn('Missing required arguments: `to` or `mediaUrl`.') return { success: false, message: 'Recipient number (to) and media URL (mediaUrl) are required.', error: 'Missing required arguments', } } // Basic E.164 format check (adjust regex for stricter validation if needed) if (!/^\+[1-9]\d{1,14}$/.test(to)) { logger.warn({ recipient: to }, 'Invalid recipient phone number format.') return { success: false, message: 'Invalid recipient number format. Use E.164 format with max 15 digits (e.g., +15551234567).', error: 'Invalid E.164 format', } } // Check if mediaUrl looks like a valid URL (basic check) try { new URL(mediaUrl); } catch (_) { logger.warn({ mediaUrl }, 'Invalid media URL format.'); return { success: false, message: 'Invalid media URL format.', error: 'Invalid URL', } } // --- Plivo Client Initialization --- const client = new plivo.Client( process.env.PLIVO_AUTH_ID, process.env.PLIVO_AUTH_TOKEN ) // --- Plivo API Call --- try { const params: MessageCreateParams = { src: process.env.PLIVO_SENDER_ID, // Sender ID from .env dst: to, // Recipient number text: text || ' ', // Plivo requires non-empty text field, even for MMS. Use a space if no text provided. type: 'mms', // Specify MMS type media_urls: [mediaUrl], // Array containing the media URL // Optional: Add URL for delivery status callbacks // url: 'YOUR_STATUS_CALLBACK_URL', // method: 'POST', } logger.debug({ params }, 'Sending request to Plivo API') const response = await client.messages.create(params) logger.info({ plivoResponse: response }, `Plivo MMS queued successfully to ${to}`) // Plivo typically returns message_uuid in an array const messageUuid = response.messageUuid?.[0] || null return { success: true, message: response.message || 'MMS successfully queued for sending.', messageUuid: messageUuid, } } catch (error) { logger.error({ error, to, mediaUrl }, 'Error sending Plivo MMS') // Attempt to extract a more specific error message from Plivo's response const plivoErrorMessage = error?.message || 'Unknown Plivo API error.' return { success: false, message: `Failed to send MMS: ${plivoErrorMessage}`, messageUuid: null, error: plivoErrorMessage, // Include Plivo's error if available } } }- Why this approach?
- Encapsulation: Keeps Plivo-specific logic isolated within this service.
- Type Safety: Uses TypeScript interfaces (
SendMmsArgs,SendMmsResponse) for better code clarity and safety. - Validation: Includes checks for environment variables and basic input formats (
to,mediaUrl). - Clear Logging: Uses Redwood's
loggerfor different levels (info, warn, error, debug) to aid troubleshooting. - Error Handling: Wraps the Plivo API call in a
try...catchblock and returns a structured response indicating success or failure, including potential error messages from Plivo. - Configuration: Reads sensitive credentials and the sender ID directly from environment variables.
text: ' ': Plivo's API often requires thetextfield even for MMS. Sending a single space satisfies this requirement if no specific text is provided.media_urls: Note the parameter name used by the Plivo Node.js SDK ismedia_urls, expecting an array of strings.
- Why this approach?
Building the GraphQL API Layer for MMS
Now, let's expose our sendMms service function through the RedwoodJS GraphQL API.
-
Define the GraphQL Mutation (SDL): Create a new file
api/src/graphql/plivoMms.sdl.tsand add the following schema definition:typescript// api/src/graphql/plivoMms.sdl.ts export const schema = gql` type PlivoMmsResponse { success: Boolean! message: String! messageUuid: String error: String } type Mutation { """ Sends an MMS message via Plivo to a US or Canadian number. Requires a publicly accessible media URL. """ sendPlivoMms( to: String! mediaUrl: String! text: String ): PlivoMmsResponse! @requireAuth # Or use @skipAuth if authentication is not required for this endpoint } `PlivoMmsResponseType: Defines the structure of the data returned by the mutation. It mirrors theSendMmsResponseinterface from our service.sendPlivoMmsMutation: Defines the mutation name, its input arguments (to,mediaUrl,text), and the response type (PlivoMmsResponse!).to: String!: Recipient number (required).mediaUrl: String!: Media URL (required).text: String: Optional text body.
@requireAuth: This directive enforces that the user must be authenticated to call this mutation. Change to@skipAuthif this specific mutation should be publicly accessible, but be cautious about potential abuse. Adjust authentication based on your application's needs. Redwood automatically wires this SDL definition to the corresponding service function (sendMmsinplivoMms.ts).
-
Testing with GraphQL Playground: Once you run
yarn rw dev, RedwoodJS provides a GraphQL Playground (usually athttp://localhost:8911/graphql) where you can test this mutation.Example Mutation Request:
graphqlmutation SendMyMms { sendPlivoMms( to: "+15551234567" # Replace with a valid E.164 test number mediaUrl: "https://media.giphy.com/media/26gscSULUcfKU7dHq/source.gif" # Example public GIF URL text: "Check out this cool GIF!" ) { success message messageUuid error } }Expected Success Response (Example):
json{ "data": { "sendPlivoMms": { "success": true, "message": "MMS successfully queued for sending.", "messageUuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "error": null } } }Expected Failure Response (Example - Invalid Number):
json{ "data": { "sendPlivoMms": { "success": false, "message": "Invalid recipient number format. Use E.164 format with max 15 digits (e.g., +15551234567).", "messageUuid": null, "error": "Invalid E.164 format" } } }Expected Failure Response (Example - Plivo API Error):
json{ "data": { "sendPlivoMms": { "success": false, "message": "Failed to send MMS: Authentication credentials invalid <or other Plivo error>", "messageUuid": null, "error": "Authentication credentials invalid <or other Plivo error>" } } }
Configuring Plivo API Credentials
This section summarizes the critical Plivo configuration steps already covered.
- Plivo Account: Ensure you have an active Plivo account. Trial accounts have limitations (see Caveats).
- API Credentials:
- Navigate to the Plivo Console Dashboard.
- Copy your
Auth IDandAuth Token. - Store these securely in your
.envfile asPLIVO_AUTH_IDandPLIVO_AUTH_TOKEN. Never commit these to version control. - Note: The Plivo Node.js SDK recommends using environment variables for authentication as the preferred method.
- MMS-Enabled Sender ID (Phone Number):
- Go to Phone Numbers -> Your Numbers in the Plivo Console.
- Verify you have a US or Canadian number with "MMS" listed under "Capabilities". Purchase one if necessary ("Buy Numbers" section).
- Copy the number in E.164 format (e.g.,
+14155551234). - Store this in your
.envfile asPLIVO_SENDER_ID.
- Media URL: The
mediaUrlyou provide must be publicly accessible over the internet. Plivo's servers need to fetch the media from this URL to attach it to the MMS. Private or localhost URLs will not work. - Geographic Restriction: Plivo supports sending MMS messages only within the US and Canada. International MMS messaging outside these two countries is not yet supported. Ensure your sender number is US/Canadian and recipient numbers are within these countries.
Error Handling and Logging Best Practices
- Error Handling: Our service function (
sendMms) implements basic error handling:- Checks for missing configuration (
.envvariables). - Performs basic input validation (required fields,
toformat,mediaUrlformat). - Uses a
try...catchblock around theclient.messages.createcall to capture exceptions from the Plivo SDK or API. - Returns a structured
SendMmsResponseobject containingsuccess: falseand anerrormessage upon failure.
- Checks for missing configuration (
- Logging: RedwoodJS's built-in
loggeris used:logger.info: Records initiation attempts and successful queuing.logger.warn: Records non-critical issues like invalid input formats before attempting the API call.logger.error: Records exceptions caught during the Plivo API interaction, including the error object.logger.debug: Can be used for more verbose logging during development (e.g., logging the exact params sent to Plivo). Adjust log levels inapi/src/lib/logger.tsor via environment variables (LOG_LEVEL) for different environments.
- Retry Mechanisms:
-
For transient network errors or temporary Plivo API issues, implementing a retry strategy can improve reliability.
-
Common approach: Exponential backoff (e.g., retry after 1s, then 2s, then 4s).
-
Libraries like
async-retrycan simplify this. -
To add retries, first install the package:
bashyarn workspace api add async-retry -
Example (Conceptual usage within the
sendMmsfunction):typescript// Inside sendMms function, replacing the try...catch block around client.messages.create import retry from 'async-retry'; // ... other imports and code ... try { // The actual Plivo API call is wrapped in the retry logic const response = await retry( async (bail, attemptNum) => { // Use attemptNum from retry try { const params: MessageCreateParams = { src: process.env.PLIVO_SENDER_ID, dst: to, text: text || ' ', type: 'mms', media_urls: [mediaUrl], }; logger.debug({ params, attempt: attemptNum }, 'Sending request to Plivo API'); const result = await client.messages.create(params); // Optional: Check for specific Plivo errors that shouldn't be retried // if (result.error && result.error === 'some_permanent_error_code') { // bail(new Error('Permanent error from Plivo, not retrying.')); // return; // bail throws, so this isn't strictly needed // } return result; // Success, return the Plivo response } catch (error) { // Don't retry certain client-side or fatal errors if (error.message.includes('invalid') || error.message.includes('Authentication')) { logger.warn({ error, attempt: attemptNum }, 'Non-retriable error detected, stopping retries.'); bail(error); // Use bail to stop retrying for these errors return; // Exit the async function for bail } // Log the retry attempt and throw the error to trigger the next retry logger.warn({ error, attempt: attemptNum }, 'Plivo API call failed, retrying...'); throw error; } }, { retries: 3, // Total number of attempts = 1 initial + 3 retries = 4 factor: 2, // Exponential backoff factor (1s, 2s, 4s) minTimeout: 1000, // Initial timeout in ms onRetry: (error, attempt) => { // This callback is invoked before each retry logger.warn(`Retrying Plivo MMS send (attempt ${attempt}) due to error: ${error.message}`); } } ); // If retry is successful, process the response logger.info({ plivoResponse: response }, `Plivo MMS queued successfully to ${to} after retries`); const messageUuid = response.messageUuid?.[0] || null; return { success: true, message: response.message || 'MMS successfully queued for sending after retries.', messageUuid: messageUuid, }; } catch (error) { // This catch block executes if all retries fail logger.error({ error, to, mediaUrl }, 'Error sending Plivo MMS after all retries'); const plivoErrorMessage = error?.message || 'Unknown Plivo API error after retries.'; return { success: false, message: `Failed to send MMS after retries: ${plivoErrorMessage}`, messageUuid: null, error: plivoErrorMessage, }; } -
Caution: Be careful not to retry errors that are definitely not transient (e.g., invalid credentials, invalid destination number). Use the
bailfunction inasync-retryto prevent retries for such cases.
-
Database Schema for MMS Message Logging
For this specific task of sending an MMS, a database isn't strictly required by the core Plivo integration itself. However, in a real-world application, you would likely want to:
- Log Message Status: Store the
messageUuidreturned by Plivo along with recipient details, timestamp, and initial status (queued). - Handle Delivery Reports: Plivo can send webhook callbacks to your application with delivery status updates (e.g.,
sent,delivered,failed). You'd need:- A database table to store message logs (
MessageLogschema). - A separate RedwoodJS function (webhook handler) to receive these callbacks.
- Logic to update the status of the corresponding message in your
MessageLogtable using themessageUuid.
- A database table to store message logs (
Example Prisma Schema (Conceptual):
// api/db/schema.prisma
model PlivoMessageLog {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
to String
from String // The Plivo sender ID used
text String?
mediaUrl String?
messageUuid String? @unique // Plivo's unique ID
status String @default("queued") // e.g., queued, sent, delivered, failed, undelivered
plivoError String? // Store error message from Plivo on failure
direction String @default("outbound") // Could also log inbound messages
// Optional: Link to user or other relevant models
// userId String?
// user User? @relation(fields: [userId], references: [id])
}Implementing the webhook handler and database logging is beyond the scope of this initial setup guide but is a recommended enhancement for production applications.
Security Best Practices for MMS Integration
- API Key Security:
- Plivo
Auth IDandAuth Tokenare stored securely in.envand accessed as environment variables. .envis excluded from Git via.gitignore.- Environment variables are configured securely in deployment environments (see Section 12).
- Plivo
- Input Validation:
- The
sendMmsservice performs basic checks on thetonumber format (E.164) andmediaUrlformat. Robust validation (e.g., using a library likelibphonenumber-jsfor phone numbers) is recommended for production. - Sanitize any
textinput if it originates directly from users to prevent injection attacks (though less critical when sending out via Plivo, still good practice).
- The
- Authentication/Authorization:
- The GraphQL mutation
sendPlivoMmsuses@requireAuth(by default). Ensure your RedwoodJS app has authentication set up (yarn rw setup auth ...) if needed. Only authenticated and authorized users should be able to trigger MMS sends if the action is tied to user activity. - If the endpoint needs to be public (
@skipAuth), implement other safeguards like API keys or stricter rate limiting.
- The GraphQL mutation
- Rate Limiting:
- To prevent abuse (accidental or malicious), implement rate limiting on the
sendPlivoMmsmutation. - This can be done using RedwoodJS directives, API gateway features (if applicable), or middleware. Limit requests per user/IP address over a specific time window.
- To prevent abuse (accidental or malicious), implement rate limiting on the
- Media URL Security: Ensure the system generating
mediaUrlvalues does not allow users to input arbitrary URLs pointing to internal resources or malicious sites. Validate the source of media URLs.
Common MMS Integration Issues and Solutions
- US/Canada Limitation: Plivo supports sending MMS messages only within the US and Canada. International MMS messaging outside these two countries is not yet supported. Attempts to send MMS to other countries will fail. Your application logic should account for this, potentially disabling the feature or warning users if the recipient is outside these regions.
- E.164 Format: Plivo requires destination (
dst) numbers in E.164 format (+followed by country code and number, e.g.,+14155551234). The E.164 specification allows a maximum of 15 digits total, with country codes ranging from 1–3 digits. Ensure your frontend or backend properly formats numbers before passing them to the service. The validation regex/^\+[1-9]\d{1,14}$/ensures compliance with E.164 (no leading zeros in country code, max 15 digits total). - Public Media URL: The
mediaUrlmust be publicly accessible. Plivo needs to download the content. Localhost URLs, URLs behind firewalls, or URLs requiring authentication will not work. Consider using cloud storage (like AWS S3, Google Cloud Storage) with public read access for the media files. - File Size/Type Limits: Plivo supports JPEG, PNG, and GIF images, as well as other image, video, and audio formats. The total size of the MMS must not exceed 5MB, and messages exceeding this limit will be marked as Failed with error code 120. Plivo supports up to 10 attachments per message. Carrier-specific limits apply: for US carriers, file sizes range from 0.6MB to 1.5MB depending on the carrier and number type (long code, toll-free, short code). For Canadian carriers, attachments should be smaller than 1MB.
- Trial Account Limitations: Plivo trial accounts can typically only send messages (SMS/MMS) to phone numbers that have been verified (sandboxed) within the Plivo console ("Phone Numbers" -> "Sandbox Numbers"). Sending to unverified numbers will fail until the account is upgraded.
Performance Optimization Strategies
For sending single MMS messages triggered by user actions, performance is usually less critical than reliability. However, consider:
- Asynchronous Sending: The current implementation is already asynchronous (
async/await). ThesendMmsfunction returns quickly after queueing the message with Plivo; it doesn't wait for final delivery. - Batching: Plivo's standard
messages.createAPI sends one message per request. For high-volume sending, investigate Plivo's Powerpack feature or bulk messaging capabilities if available, which might offer more optimized throughput, though potentially with different API interactions. - Media Hosting: Ensure your media hosting solution (where
mediaUrlpoints) is performant and scalable to handle Plivo fetching the files quickly. Using a Content Delivery Network (CDN) for media files is recommended. - Database Writes: If logging messages to a database (Section 6), ensure database writes are efficient and don't block the main request thread for too long, especially if handling status callbacks. Consider background job queues for logging if performance becomes an issue.
Monitoring and Observability Setup
- Logging: We've implemented structured logging using Redwood's
logger. Ensure logs are aggregated in your production environment (e.g., using services like Datadog, Logtail, Papertrail, or cloud provider logging). Monitor logs for error patterns (level: 'error'orlevel: 'warn'). - Plivo Logs: The Plivo Console provides detailed logs for all messages ("Messaging" -> "Logs"). Use this to track message statuses (
Queued,Sent,Delivered,Failed,Undelivered), troubleshoot delivery issues, and view costs. Filter bymessageUuid. - Error Tracking: Integrate an error tracking service (e.g., Sentry, Bugsnag) with your RedwoodJS API side. This will capture unhandled exceptions and provide detailed context (stack traces, request data). RedwoodJS has integrations for some providers (
yarn rw setup monitoring ...). - Health Checks: Implement a basic health check endpoint in your RedwoodJS API (e.g.,
/health) that verifies database connectivity and potentially checks if essential environment variables (PLIVO_...) are loaded. - Key Metrics (via Plivo Dashboard/API):
- Delivery Rate (% Delivered)
- Failure Rate (% Failed/Undelivered)
- Latency (Time from Queueing to Sent/Delivered - available in logs)
- Costs
- Application Metrics: Monitor the performance of the
sendPlivoMmsGraphQL mutation (request rate, error rate, duration) using your Application Performance Monitoring (APM) tool or logging platform.
Troubleshooting Common Plivo MMS Errors
- Error:
Authentication credentials invalid- Cause: Incorrect
PLIVO_AUTH_IDorPLIVO_AUTH_TOKENin.env. - Solution: Double-check credentials in the Plivo Console dashboard and update
.env. Ensure the environment variables are correctly loaded in your deployment environment.
- Cause: Incorrect
- Error:
Invalid 'src' parameterorThis caller ID is not allowed...- Cause: The
PLIVO_SENDER_IDin.envis not a valid Plivo number associated with your account, is not MMS-enabled, or is potentially of a type not allowed for sending MMS (e.g., a short code not provisioned for MMS). - Solution: Verify the number in the Plivo Console (Phone Numbers -> Your Numbers). Ensure it's E.164 format, has MMS capability enabled, and is associated with your Auth ID.
- Cause: The
- Error:
Invalid 'dst' parameterorDestination number is not valid for MMS- Cause: The
tonumber is not in valid E.164 format, or you are attempting to send MMS outside the US/Canada. - Solution: Ensure
tonumber starts with+and country code. Verify the recipient is in the US or Canada.
- Cause: The
- Error:
Media URL could not be downloadedor similar media error- Cause: The
mediaUrlprovided is not publicly accessible, is malformed, points to an unsupported file type, or exceeds size limits. - Solution: Verify the URL is correct and publicly reachable (test in a browser incognito window). Check Plivo's media requirements (size, type). Ensure the hosting server is responding correctly.
- Cause: The
- MMS Not Received (but Plivo logs show
SentorDelivered)- Cause: Carrier filtering, recipient device issues (MMS disabled, poor signal, blocking), incorrect destination number format (even if validated by Plivo initially).
- Solution: Verify the recipient number exactly. Check recipient device settings. Consult carrier-specific MMS troubleshooting guides. Check Plivo logs for detailed error codes if status becomes
FailedorUndelivered.
- Trial Account Limitation: Messages fail to send to numbers not verified in the Plivo Console ("Sandbox Numbers"). Solution: Verify the recipient number in the sandbox or upgrade your Plivo account.
- Environment Variables Not Loaded: Service fails with "credentials missing" errors, especially after deployment. Solution: Ensure
.envvariables are correctly configured in your hosting provider's environment variable settings (Vercel, Netlify, Render, etc.). Do not commit the.envfile.
Deployment and Production Considerations
Deploying your RedwoodJS application with Plivo integration follows standard Redwood procedures, with a key focus on environment variables.
- Choose a Hosting Provider: Select a provider compatible with RedwoodJS (e.g., Vercel, Netlify, Render, AWS Serverless).
- Configure Environment Variables:
- Crucial Step: In your hosting provider's dashboard/settings, securely add the same environment variables defined in your local
.envfile:PLIVO_AUTH_IDPLIVO_AUTH_TOKENPLIVO_SENDER_ID
- Do NOT commit your
.envfile to Git. Use the hosting provider's mechanism for managing secrets.
- Crucial Step: In your hosting provider's dashboard/settings, securely add the same environment variables defined in your local
- Build Command: Typically
yarn rw build. - Deployment: Follow your hosting provider's instructions for deploying a RedwoodJS application. This usually involves connecting your Git repository and configuring build settings.
- CI/CD: Integrate deployment into your CI/CD pipeline (e.g., GitHub Actions, GitLab CI). Ensure the pipeline has secure access to the production environment variables during the build/deploy process if needed, but preferably configure them directly in the hosting environment.
- Testing in Production: After deployment, perform a test send from your live application to ensure the configuration is correct and messages are being sent successfully. Check Plivo logs for confirmation.
Frequently Asked Questions About Plivo MMS in RedwoodJS
How do I send MMS messages with images in RedwoodJS?
To send MMS messages with images in RedwoodJS, install the Plivo Node.js SDK (yarn workspace api add plivo), create a service function that uses client.messages.create() with type: 'mms' and media_urls: [imageUrl], and expose it through a GraphQL mutation. The image URL must be publicly accessible. Configure your Plivo credentials (PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, PLIVO_SENDER_ID) in your .env file. The sender number must be MMS-enabled and US/Canadian for US/Canada delivery.
What is the difference between SMS and MMS in Plivo?
SMS (Short Message Service) sends text-only messages up to 160 characters per segment, while MMS (Multimedia Messaging Service) allows sending images, GIFs, audio, and video along with text. In Plivo's API, you specify type: 'sms' for SMS or type: 'mms' for MMS. MMS requires a media_urls parameter with publicly accessible URLs. Plivo MMS is only supported for US and Canada destinations, whereas SMS has broader international coverage. MMS typically costs more per message than SMS.
Can I send MMS to international numbers with Plivo?
No, Plivo MMS is only supported for US and Canada destinations. International MMS messaging outside these two countries is not yet supported. If you attempt to send MMS to numbers outside the US/Canada, the API request will fail. Both your sender number (configured as PLIVO_SENDER_ID) and recipient number must be US or Canadian numbers in E.164 format (e.g., +14155551234 for US, +16135551234 for Canada). For international messaging, use SMS instead of MMS.
What file formats and sizes does Plivo MMS support?
Plivo supports JPEG, PNG, and GIF images, as well as other image, video, and audio formats. The total size of the MMS must not exceed 5MB, with up to 10 attachments supported per message. Carrier-specific file size limits apply: US carriers range from 0.6MB (Verizon short code) to 1.5MB (T-Mobile long code), while Canadian carriers recommend keeping attachments under 1MB. The media must be hosted at a publicly accessible HTTPS URL. Messages exceeding 5MB total will fail with Plivo error code 120.
How do I validate phone numbers in E.164 format for Plivo MMS?
Use the regex pattern /^\+[1-9]\d{1,14}$/ to validate E.164 format phone numbers. This ensures the number starts with +, has no leading zeros in the country code, and contains a maximum of 15 digits total (country code 1–3 digits + subscriber number). For example, valid numbers include +14155551234 (US) or +442071234567 (UK). For more robust validation including country-specific rules, use the libphonenumber-js library: yarn workspace api add libphonenumber-js.
Why is my Plivo MMS failing with "Media URL could not be downloaded"?
This error occurs when Plivo cannot access the media URL you provided in the media_urls parameter. Common causes: (1) URL is not publicly accessible (localhost, behind firewall, requires authentication), (2) URL returns 404 or 500 errors, (3) SSL certificate issues with HTTPS URLs, (4) file format unsupported, (5) file size exceeds limits. Solution: Test the URL in an incognito browser window, ensure it's publicly accessible via HTTPS, host media on reliable CDN services like AWS S3 or Cloudinary with public read permissions.
How do I test Plivo MMS integration in development?
Test in development by: (1) Running yarn rw dev to start your RedwoodJS server, (2) Opening GraphQL Playground at http://localhost:8911/graphql, (3) Using a mutation like sendPlivoMms(to: "+15551234567", mediaUrl: "https://example.com/image.jpg", text: "Test") with a verified sandbox number from your Plivo trial account. Monitor server logs for errors. Test with publicly hosted images (e.g., from Imgur or Giphy). For trial accounts, you must verify recipient numbers in the Plivo Console under "Sandbox Numbers" before testing.
What's the cost of sending MMS with Plivo?
Plivo MMS pricing varies by destination and is typically higher than SMS. While exact MMS pricing per message is not explicitly published on Plivo's public pricing pages, third-party sources indicate costs are significantly higher than SMS rates (which start at $0.005-$0.007 per message for US). For current MMS pricing, check the Plivo SMS Pricing Page for United States or contact Plivo sales directly. New accounts receive free trial credit ($5 for new users). Monitor usage in the Plivo Console under "Account" → "Usage" to track costs. Consider implementing rate limiting to control expenses in production applications.
Frequently Asked Questions
How to send MMS messages with RedwoodJS?
You can send MMS messages by integrating Plivo's MMS API into your RedwoodJS application. This involves creating a Redwood service that uses the Plivo Node.js SDK and exposing this service via a GraphQL mutation. The service handles interaction with the Plivo API, sending media URLs and optional text to recipients.
What is Plivo used for in RedwoodJS?
Plivo is a cloud communications platform that enables sending MMS, SMS, and voice messages. In a RedwoodJS application, the Plivo Node.js SDK is used within a service to interact with the Plivo API for sending multimedia messages, including images and GIFs.
Why use Plivo for sending MMS in RedwoodJS?
Plivo provides a convenient API and Node.js SDK for integrating MMS functionality into a RedwoodJS backend. It allows for richer communication, handling media that standard SMS cannot, and offers robust features for managing MMS campaigns.
When should I use a Plivo MMS service?
Use a Plivo MMS service when you need to send messages containing rich media like images, GIFs, or other files directly from your RedwoodJS application. This is ideal for user engagement, notifications, or marketing campaigns in the US and Canada.
Can I send MMS to international numbers with Plivo?
Plivo's MMS sending, as implemented in this RedwoodJS guide, is currently limited to US and Canadian numbers. Attempts to send to other regions will fail, so your application logic should handle these limitations.
How to set up Plivo in a RedwoodJS project?
First, install the Plivo Node.js SDK using `yarn workspace api add plivo`. Then, configure environment variables (`PLIVO_AUTH_ID`, `PLIVO_AUTH_TOKEN`, `PLIVO_SENDER_ID`) in a `.env` file. These credentials are essential for accessing the Plivo API and setting the appropriate sender number.
What is the PLIVO_SENDER_ID in RedwoodJS?
The `PLIVO_SENDER_ID` environment variable stores your MMS-enabled Plivo phone number in E.164 format (e.g., +14155551234). This is the number that will appear as the sender of the MMS messages.
Where do I find my Plivo Auth ID and Auth Token?
You can find your Plivo Auth ID and Auth Token on the main dashboard overview page after logging in to your Plivo Console at https://console.plivo.com/.
How to handle Plivo MMS errors in RedwoodJS?
The provided `sendMms` service includes error handling for missing environment variables, invalid input formats, and Plivo API errors. It returns a structured response, including a success flag, message, and error details for easier debugging and client feedback.
What format should the media URL be for Plivo MMS?
The `mediaUrl` provided to the Plivo API must be a publicly accessible URL. Plivo's servers need to download the media from this URL to attach it to the MMS message. Private or localhost URLs will not work.
How to configure environment variables for Plivo in production?
During deployment to your chosen provider, add the `PLIVO_AUTH_ID`, `PLIVO_AUTH_TOKEN`, and `PLIVO_SENDER_ID` environment variables in the hosting platform's settings. Never commit your .env file containing these secrets.
How do I create a RedwoodJS service for sending Plivo MMS?
Use the Redwood CLI command `yarn rw g service plivoMms` to generate the necessary service files. Then, implement the `sendMms` function in `api/src/services/plivoMms/plivoMms.ts`, using the provided code example, to handle MMS sending logic.
What's the correct way to add the Plivo SDK to a RedwoodJS project?
Install the Plivo SDK specifically into the `api` workspace using the command `yarn workspace api add plivo`. This ensures the package is only added as a dependency for the backend where it's required.
How do I structure the GraphQL mutation for sending Plivo MMS?
Define the GraphQL mutation in a new file named `api/src/graphql/plivoMms.sdl.ts`. The schema should include input arguments for the recipient number (`to`), media URL (`mediaUrl`), optional text (`text`), and a response type indicating success or failure.