This guide provides a step-by-step walkthrough for building a Node.js application capable of sending Multimedia Messaging Service (MMS) messages using the Sinch API. We will cover everything from initial project setup to deployment considerations, focusing on creating a robust and production-ready implementation.
By the end of this guide, you will have a functional Node.js script that can send MMS messages, including text and media files, via Sinch, along with an understanding of error handling, security, and best practices.
Project Overview and Goals
Goal: To create a reliable Node.js service that sends MMS messages containing text and media (images, audio, video) to specified recipients using the Sinch MMS API.
Problem Solved: This implementation enables applications to programmatically send rich media content to users via the standard MMS channel, useful for notifications, marketing, alerts, or user engagement requiring more than plain text SMS.
Technologies Used:
- Node.js: A JavaScript runtime environment chosen for its asynchronous, event-driven nature, making it well-suited for I/O-heavy operations like API calls. Its large ecosystem (npm) provides helpful libraries.
- Express.js (Optional but Recommended): A minimal and flexible Node.js web application framework. While not strictly required for the basic sending script (
index.js
running directly), it's included as an optional example to demonstrate how to wrap the sending logic in an API endpoint or potentially handle incoming delivery reports via webhooks later. - Axios: A promise-based HTTP client for Node.js, used to make requests to the Sinch API. Chosen for its ease of use and widespread adoption.
- dotenv: A module to load environment variables from a
.env
file intoprocess.env
, crucial for managing sensitive credentials securely. - Sinch MMS API: The third-party service providing the MMS sending functionality.
System Architecture:
+----------------------+ +-------------------+ +-------------+ +---------+ +-------------------+
| User / Trigger Event | -----> | Your Node.js App | -----> | Sinch MMS | -----> | Carrier | -----> | Recipient's Phone |
| (e.g., Button Click) | | (Axios + Optional | | API | | Network | | (Receives MMS) |
| | | Express) | +-------------+ +---------+ +-------------------+
+----------------------+ +-------------------+ | ^ ^
| | (API Credentials) | (Media Fetch)
v | |
+---------+ +------------------+
| .env | | Media URL Server |
| (Secrets)| | (e.g., S3, CDN) |
+---------+ +------------------+
Expected Outcome: A Node.js script, with index.js
as the entry point and core logic in src/sendMmsService.js
, that can be executed to send an MMS message with specified parameters (recipient, sender number, subject, text, media URLs). If the optional Express code is uncommented, a simple API endpoint (/send-mms
) could trigger this functionality.
Prerequisites:
- Node.js and npm (or yarn) installed.
- A Sinch account with an active MMS-enabled Service Plan or Campaign.
- Your Sinch Service Plan ID (or Campaign ID) and API Token.
- A provisioned phone number (Short Code, Toll-Free, or 10DLC) associated with your Sinch account, capable of sending MMS.
- URLs for the media files (images, audio, video, etc.) you want to send. These URLs must be publicly accessible, and the server hosting them must return a
Content-Length
header in the HTTP response. - Familiarity with JavaScript and basic command-line operations.
1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies.
-
Create Project Directory: Open your terminal or command prompt and create a new directory for the project.
mkdir sinch-mms-sender cd sinch-mms-sender
-
Initialize Node.js Project: Initialize the project using npm. The
-y
flag accepts default settings.npm init -y
This creates a
package.json
file. -
Install Dependencies: Install
axios
for making HTTP requests anddotenv
for managing environment variables. We'll also installexpress
for the optional API wrapper example.npm install axios dotenv express
This command adds these packages to your
node_modules
directory and lists them as dependencies inpackage.json
. -
Create Project Structure: Set up a basic structure for clarity:
sinch-mms-sender/ ├── node_modules/ ├── src/ │ └── sendMmsService.js # Logic for interacting with Sinch ├── .env # Environment variables (API keys, etc.) - DO NOT COMMIT ├── .gitignore # Specifies intentionally untracked files ├── index.js # Main application entry point / Optional Express server └── package.json
-
Configure
.gitignore
: Create a.gitignore
file in the root directory to prevent committing sensitive information and unnecessary files:# .gitignore node_modules/ .env npm-debug.log* yarn-debug.log* yarn-error.log*
-
Set up Environment Variables (
.env
): Create a file named.env
in the project root. This file will hold your sensitive Sinch credentials. Never commit this file to version control. Use the standardKEY=VALUE
format. Quotes are generally not needed unless the value contains spaces or special characters.# .env - DO NOT COMMIT TO GIT # Sinch Credentials - Obtain from your Sinch Dashboard # Path: SMS > APIs > Your Service Plan ID > REST API Configuration SINCH_SERVICE_PLAN_ID=YOUR_SERVICE_PLAN_OR_CAMPAIGN_ID SINCH_API_TOKEN=YOUR_API_TOKEN # Your provisioned Sinch number (international format, e.g., +1...) SINCH_FROM_NUMBER=+1xxxxxxxxxx # Sinch API Base URL - CRITICAL: VERIFY THIS FOR YOUR ACCOUNT AND REGION # Check your specific region (e.g., us, eu, ca, au) and the exact endpoint path. # The path might be /v1/submissions, /v1/projects/.../messages, or something else. # Consult the Sinch documentation or your dashboard for the correct URL. # The example below is illustrative ONLY and likely needs modification. SINCH_API_BASE_URL=https://us.mms.api.sinch.com/v1/some-path-specific-to-your-account # URL of the media file(s) you want to send # Ensure these are publicly accessible and return Content-Length header MEDIA_IMAGE_URL=https://your-cdn.com/path/to/image.jpg MEDIA_VIDEO_URL=https://your-cdn.com/path/to/video.mp4
SINCH_SERVICE_PLAN_ID
/YOUR_CAMPAIGN_ID
: Found in your Sinch Dashboard, often under SMS > APIs or similar sections related to your messaging setup. It identifies the specific configuration/billing plan.SINCH_API_TOKEN
: Your secret API key, generated in the Sinch Dashboard alongside the Service Plan ID. Treat this like a password.SINCH_FROM_NUMBER
: The MMS-enabled number associated with your Sinch account that will appear as the sender. Use international format (e.g.,+12223334444
).SINCH_API_BASE_URL
: The base URL for the Sinch MMS API endpoint. Crucially, verify the correct endpoint for your account and region. The structure varies. Check the Sinch dashboard or specific API documentation provided during your account setup. The example provided is a placeholder and likely incorrect for your specific use case. Using the wrong URL is a common cause of errors.MEDIA_..._URL
: Placeholder URLs for your media content.
2. Implementing Core Functionality: Sending MMS
We'll create a dedicated service module to handle the logic of sending the MMS message via the Sinch API.
-
Create
src/sendMmsService.js
: This file will contain the function to construct and send the API request.// src/sendMmsService.js const axios = require('axios'); // Load environment variables (ensure dotenv is configured in the entry point, e.g., index.js) const servicePlanId = process.env.SINCH_SERVICE_PLAN_ID; const apiToken = process.env.SINCH_API_TOKEN; const sinchApiBaseUrl = process.env.SINCH_API_BASE_URL; // CRITICAL: Ensure this is the correct URL from .env /** * Sends an MMS message using the Sinch API. * * @param {object} params - The parameters for the MMS message. * @param {string} params.to - Recipient phone number in international format (e.g., +1xxxxxxxxxx). * @param {string} params.from - Sender phone number (your Sinch number) in international format. * @param {string} [params.subject] - MMS subject line (max 80 chars, 40 recommended). Verify key name ('message-subject') with docs. * @param {Array<object>} params.slides - An array of slide objects. Max 8 slides. Verify structure with docs. * Each slide must contain message-text and/or one media type. * Example: [{ image: { url: '...' }, 'message-text': '...' }, { video: { url: '...' } }] * @param {string} [params.fallbackText] - Text for SMS fallback if MMS fails or is disabled (required if fallback enabled). Verify key name ('fallback-sms-text') with docs. * @param {boolean} [params.disableFallbackSms=false] - Set to true to disable SMS fallback entirely. Verify key name ('disable-fallback-sms') with docs. * @param {boolean} [params.disableFallbackSmsLink=false] - Set to true to remove the media link from fallback SMS. Verify key name ('disable-fallback-sms-link') with docs. * @param {string} [params.clientReference] - Optional client-supplied identifier (max 64 chars). Verify key name ('client-reference') with docs. * @returns {Promise<object>} - A promise resolving with the Sinch API response data. * @throws {Error} - Throws an error if the API call fails. */ async function sendMmsMessage({ to, from, subject, slides, fallbackText, disableFallbackSms = false, disableFallbackSmsLink = false, clientReference, }) { if (!servicePlanId || !apiToken || !sinchApiBaseUrl) { throw new Error('Sinch API credentials or base URL are not configured correctly in .env. Verify SINCH_API_BASE_URL.'); } if (!to || !from || !slides || slides.length === 0) { throw new Error('Required parameters (to, from, slides) are missing.'); } if (!disableFallbackSms && !fallbackText) { console.warn('Warning: Fallback SMS is enabled but fallback-sms-text is not provided. It might be required by Sinch depending on your configuration.'); // Depending on Sinch validation, you might want to throw an error here: // throw new Error('fallback-sms-text is required when fallback SMS is enabled.'); } if (slides.length > 8) { throw new Error('Maximum of 8 slides allowed per MMS message. Verify limit with Sinch documentation.'); } // Construct the Sinch API request payload. // NOTE: Verify ALL keys ('action', 'service-id', 'message-subject', etc.) and structure against the official Sinch API documentation for the 'sendmms' action. const payload = { action: 'sendmms', // Specifies the MMS sending action 'service-id': servicePlanId, // Your campaign/service plan ID to: to, // Recipient number from: from, // Your Sinch sender number slide: slides, // Array of slide objects containing media/text ...(subject && { 'message-subject': subject }), // Add subject if provided ...(fallbackText && { 'fallback-sms-text': fallbackText }), // Add fallback text if provided 'disable-fallback-sms-link': disableFallbackSmsLink, 'disable-fallback-sms': disableFallbackSms, // 'fallback-sms-link-expiration': 'ISO8601_DATE_FORMAT', // Optional: Defaults to 1 year // 'mms-expiry-timestamp': 'ISO8601_DATE_FORMAT', // Optional: Defaults to 3 days ...(clientReference && { 'client-reference': clientReference }), // Add client reference if provided 'cache-content': true, // Recommended: Allows Sinch to cache media for efficiency }; const config = { headers: { 'Content-Type': 'application/json; charset=utf-8', 'Authorization': `Bearer ${apiToken}` // Use Bearer token authentication } }; console.log(`Sending MMS request to ${to} via Sinch endpoint: ${sinchApiBaseUrl}`); console.log('Payload:', JSON.stringify(payload, null, 2)); // Log the payload for debugging try { // Use the configured base URL. Ensure it points to the correct MMS endpoint. const response = await axios.post(sinchApiBaseUrl, payload, config); console.log('Sinch API Response Status:', response.status); console.log('Sinch API Response Data:', response.data); // NOTE: Verify the success condition based on Sinch API documentation. // It might involve checking response.status, response.data.status, or other fields. if (response.status >= 200 && response.status < 300 && response.data /* && response.data.status === 'success' */ ) { // Adjust success check as needed console.log(`MMS successfully accepted by Sinch for delivery to ${to}. Tracking ID (if available): ${response.data['tracking-id'] || 'N/A'}`); return response.data; // Return the success response } else { // Handle cases where the API returns 2xx but indicates failure in the body_ or non-2xx status const errorDetails = response.data ? JSON.stringify(response.data) : `HTTP Status ${response.status}`; console.error('Sinch API indicated failure:'_ errorDetails); throw new Error(`Sinch API request failed: ${errorDetails}`); } } catch (error) { console.error('Error sending MMS via Sinch:'_ error.message); if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.error('Sinch API Error Status:'_ error.response.status); console.error('Sinch API Error Data:'_ JSON.stringify(error.response.data_ null_ 2)); throw new Error(`Sinch API Error ${error.response.status}: ${JSON.stringify(error.response.data)}`); } else if (error.request) { // The request was made but no response was received console.error('Sinch API Error: No response received.'_ error.request); throw new Error('Sinch API Error: No response received from server.'); } else { // Something happened in setting up the request that triggered an Error console.error('Sinch API Error: Request setup failed.'_ error.message); throw new Error(`Request setup failed: ${error.message}`); } } } module.exports = { sendMmsMessage };
-
Create Entry Point (
index.js
): This file will load environment variables_ import the service_ and call the sending function. It also includes commented-out code for an optional Express server.// index.js require('dotenv').config(); // Load .env variables into process.env EARLY const { sendMmsMessage } = require('./src/sendMmsService'); // --- Configuration for the MMS Message --- const recipientNumber = ""+1yyyyyyyyyy""; // Target phone number (replace with actual_ use E.164 format) const senderNumber = process.env.SINCH_FROM_NUMBER; // Your Sinch Number from .env (E.164 format) // Define the slides for the MMS // Each object in the array represents one slide. // A slide can contain text and/or ONE media element (image_ audio_ video_ etc.). // Ensure media URLs are public and return a Content-Length header. // Verify slide structure and keys ('image'_ 'message-text'_ etc.) with Sinch docs. const mmsSlides = [ { image: { url: process.env.MEDIA_IMAGE_URL }_ // Use URL from .env 'message-text': ""Check out this image!"" // Text for the first slide }_ // Example of a second slide with video (optional) // { // video: { url: process.env.MEDIA_VIDEO_URL }_ // Use URL from .env // 'message-text': ""Here's a video too."" // Text for the second slide // }_ // Example of a text-only slide (optional) // { // 'message-text': ""Just some additional text on its own slide."" // } ]; const mmsParams = { to: recipientNumber_ from: senderNumber_ subject: ""MMS Test from Node.js""_ // Optional subject slides: mmsSlides_ fallbackText: ""View your MMS content here: [link] - This text will be sent if MMS fails. The link part is often handled by Sinch automatically if not disabled.""_ // Required if fallback is enabled (default) // disableFallbackSms: false_ // Default is false (fallback enabled) // disableFallbackSmsLink: false_ // Default is false (link included in fallback) clientReference: `my-app-${Date.now()}` // Optional: Unique ID for tracking }; // --- Function to Trigger Sending --- async function sendTestMms() { if (!senderNumber || !recipientNumber) { console.error(""Error: Sender or recipient number is missing. Check .env and index.js configuration.""); return; } if (!process.env.SINCH_API_BASE_URL || !process.env.SINCH_SERVICE_PLAN_ID || !process.env.SINCH_API_TOKEN) { console.error(""Error: Sinch API configuration missing in .env file. Please check SINCH_SERVICE_PLAN_ID_ SINCH_API_TOKEN_ and SINCH_API_BASE_URL.""); return; } console.log(`Attempting to send MMS to ${recipientNumber} from ${senderNumber}...`); try { const result = await sendMmsMessage(mmsParams); console.log('MMS Sending Process Initiated Successfully:'_ result); } catch (error) { console.error('Failed to send MMS:'_ error.message); // Implement more robust error handling/retry logic here if needed (see Section 4) } } // --- Execute the Sending Function --- // This runs only when the script is executed directly (`node index.js`) // If you uncomment the Express server below_ you might want to comment this out. if (require.main === module) { sendTestMms(); } // --- Optional: Express Server Setup --- // Uncomment this section if you want to wrap the sender in a simple API. // Ensure you have run `npm install express`. /* const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.use(express.json()); // Middleware to parse JSON bodies // Simple health check endpoint app.get('/health'_ (req_ res) => { res.status(200).send('OK'); }); // API endpoint to trigger sending MMS app.post('/send-mms', async (req, res) => { console.log('Received request to /send-mms'); // Basic validation (in a real app, use a library like Joi or express-validator) const { to, subject, slides, fallbackText } = req.body; const from = process.env.SINCH_FROM_NUMBER; if (!to || !slides || !Array.isArray(slides) || slides.length === 0) { return res.status(400).json({ error: 'Missing required fields: to, slides' }); } if (!from) { return res.status(500).json({ error: 'Sender number not configured in .env' }); } if (!process.env.SINCH_API_BASE_URL || !process.env.SINCH_SERVICE_PLAN_ID || !process.env.SINCH_API_TOKEN) { console.error(""API Error: Sinch configuration missing.""); return res.status(500).json({ error: 'Internal server configuration error.' }); } const params = { to, from, subject, slides, fallbackText, // Make sure this is provided if fallback is enabled clientReference: `api-${Date.now()}` }; try { const result = await sendMmsMessage(params); // Use 202 Accepted as the request is queued, not instantly delivered res.status(202).json({ message: 'MMS accepted for delivery by Sinch', details: result }); } catch (error) { console.error('API Error sending MMS:', error.message); // Avoid exposing detailed internal errors to the client res.status(500).json({ error: 'Failed to send MMS due to an internal server error.' }); } }); // Start the server only if running the script directly // Note: If you uncomment this, comment out the direct `sendTestMms()` call above. if (require.main === module) { app.listen(port, () => { console.log(`MMS Sender API listening at http://localhost:${port}`); }); } module.exports = app; // Export app for potential testing */
3. Integrating with Sinch (Configuration Details)
This section reiterates the critical configuration aspects covered during setup.
- API Credentials:
SINCH_SERVICE_PLAN_ID
/ Campaign ID: Identifies your specific Sinch messaging configuration.SINCH_API_TOKEN
: Your secret key for authenticating requests.- Location: Sinch Customer Dashboard -> SMS -> APIs -> Select your Service Plan ID -> REST API Configuration. Click ""Show"" to reveal the API Token. Ensure you copy the correct values.
- Security: Store these securely in the
.env
file and ensure.env
is listed in.gitignore
. In production, use environment variable management provided by your hosting platform (e.g., AWS Secrets Manager, Heroku Config Vars, Docker secrets).
- Sender Number (
SINCH_FROM_NUMBER
):- Format: Must be in international E.164 format (e.g.,
+1...
,+44...
). - Capability: Must be an MMS-enabled number provisioned on your Sinch account and associated with the Service Plan ID being used.
- Location: View your numbers in the Sinch Dashboard, typically under ""Numbers"" or associated with your Service Plan.
- Format: Must be in international E.164 format (e.g.,
- API Endpoint (
SINCH_API_BASE_URL
):- Region: Sinch operates in multiple regions (us, eu, etc.). The base URL is region-specific.
- Path: The exact path (
/v1/submissions
,/v1/projects/{PROJECT_ID}/messages
, etc.) can vary significantly depending on the specific Sinch MMS API version or product variant you are using. - Verification: THIS IS CRUCIAL. Double-check and triple-check the correct API endpoint URL for your specific account in the Sinch documentation or dashboard. Using the wrong endpoint (even the example provided in this guide) will result in failures (e.g., 404 Not Found, authentication errors, or unexpected behavior). Do not assume the example URL is correct.
- Media URLs:
- Accessibility: Must be publicly reachable via HTTP GET requests from Sinch's servers.
Content-Length
Header: The server hosting the media MUST return aContent-Length
header indicating the file size. Failure to do so will cause the Sinch API request to fail, often with a 400 Bad Request error related to content fetching. CDNs usingTransfer-Encoding: chunked
withoutContent-Length
can be problematic.Content-Type
Header: The server should also return a validContent-Type
header (e.g.,image/jpeg
,video/mp4
). While Sinch might infer from extensions, relying on the correct header is best practice.application/octet-stream
might work if the extension is correct but can be rejected.
4. Error Handling, Logging, and Retries
Robust applications need to handle failures gracefully.
-
Error Handling Strategy:
- The
sendMmsService.js
uses atry...catch
block around theaxios.post
call. - It differentiates between API errors (Sinch responds with non-2xx status or potentially a failure status in the body) and network/request setup errors.
- Log detailed error information (status code, response body) internally for debugging but avoid exposing sensitive details in API responses if building a web service.
- The
-
Logging:
- Currently uses
console.log
andconsole.error
. - Production: Use a dedicated logging library (like
winston
orpino
) to:- Write logs to files or centralized logging services (e.g., Datadog, Logstash, CloudWatch Logs).
- Set different log levels (info, warn, error, debug).
- Include timestamps and potentially request IDs for better correlation.
- Structure logs as JSON for easier parsing.
- Example Logging: Log the request payload (mask sensitive data if necessary), the success response (including
tracking-id
if available), and detailed error responses from Sinch.
- Currently uses
-
Retry Mechanisms (Client-Side):
- Sinch handles the retries for delivering the MMS to the carrier/handset after successfully accepting the API request.
- Your application should handle retries for the initial API call to Sinch if it fails due to transient network issues or temporary Sinch API unavailability (e.g., 5xx errors, network timeouts).
- Strategy: Implement exponential backoff. Wait longer between retries after repeated failures.
- Recommendation: For production, use a robust library like
axios-retry
to handle this automatically. - Conceptual Manual Implementation: The following snippet illustrates the concept of exponential backoff within the
catch
block. It is simplified and requires proper state management (like trackingretryCount
) in a real implementation.
// Simplified retry concept - use a library like axios-retry for production } catch (error) { console.error('Error sending MMS via Sinch:', error.message); // Assume retryCount is managed externally (e.g., passed into the function or managed in a loop) let currentRetryAttempt = /* Get current retry count, e.g., from function args or state */; const MAX_RETRIES = 3; const BASE_DELAY_MS = 1000; let shouldRetry = false; if (error.response && [500, 502, 503, 504].includes(error.response.status)) { shouldRetry = true; // Retry on common server errors } else if (!error.response && error.request) { shouldRetry = true; // Retry on network errors/timeouts where no response was received } if (shouldRetry && currentRetryAttempt < MAX_RETRIES) { const nextRetryAttempt = currentRetryAttempt + 1; // Calculate delay: 2^(retryAttempt - 1) * baseDelay. // e.g._ Attempt 1: 2^0 * 1000 = 1000ms; Attempt 2: 2^1 * 1000 = 2000ms; Attempt 3: 2^2 * 1000 = 4000ms const delay = BASE_DELAY_MS * Math.pow(2_ currentRetryAttempt); console.warn(`Retrying MMS send (Attempt ${nextRetryAttempt}/${MAX_RETRIES}) after ${delay}ms...`); await new Promise(resolve => setTimeout(resolve, delay)); // In a real implementation, you would call the sending function again here, // passing the incremented retry count, or use a loop structure. // Example: return sendMmsMessage(params, nextRetryAttempt); // Requires function signature change } else { // Log final failure, potentially push to a dead-letter queue console.error(`MMS send failed after ${currentRetryAttempt} attempts or due to non-retryable error.`); // Throw the original or a new error based on the final failure throw new Error(`Sinch API request failed definitively: ${error.message}`); } }
5. Security Features
Security is paramount, especially when handling API keys and user data.
- API Key Security:
- NEVER hardcode API keys (
SINCH_API_TOKEN
) in your source code. - Use environment variables (
.env
locally, platform-specific secrets in deployment). - Ensure
.env
is in.gitignore
. - Restrict access to production environment variables. Rotate keys periodically.
- NEVER hardcode API keys (
- Input Validation:
- If building an API: Validate all incoming request data (
to
number format/validity,subject
length,slides
structure and content, URL formats). Use libraries likeJoi
orexpress-validator
. Sanitize inputs to prevent injection attacks. - Number Formatting: Ensure
to
andfrom
numbers are strictly in E.164 format before sending to Sinch. - URL Validation: Check that media URLs are valid HTTP/HTTPS URLs. Consider adding checks to prevent Server-Side Request Forgery (SSRF) if URLs come from untrusted user input.
- If building an API: Validate all incoming request data (
- Rate Limiting:
- If building an API: Implement rate limiting (e.g., using
express-rate-limit
) on your endpoints to prevent abuse and ensure fair usage. - Be mindful of Sinch's API rate limits as well (consult their documentation for your specific plan/endpoint). Implement client-side throttling, queuing, or delays if you need to send high volumes to avoid hitting Sinch limits.
- If building an API: Implement rate limiting (e.g., using
- HTTPS: Ensure all communication with the Sinch API uses HTTPS (which
axios
does by default forhttps://
URLs). If hosting media, ensure it's served over HTTPS. If running an Express API, ensure it runs behind a TLS-terminating proxy (like Nginx or a load balancer) or uses Node'shttps
module in production. - Error Message Handling: Avoid leaking internal system details, sensitive configuration, or stack traces in error messages sent back to clients (if building an API). Log detailed errors internally but provide generic, user-friendly error messages externally.
6. Handling Special Cases
Real-world usage involves various edge cases.
- International Number Formatting: Always use the E.164 international format for
to
andfrom
numbers (e.g.,+17745559144
,+447123456789
). Sinch relies on the country code for routing. Do not include dialing prefixes like00
or punctuation. Validate formats rigorously. - Fallback SMS:
- Understand the purpose and interaction of
fallback-sms-text
,disable-fallback-sms
, anddisable-fallback-sms-link
parameters. Verify these parameter names with Sinch documentation. - If
disable-fallback-sms
isfalse
(default),fallback-sms-text
is generally required by Sinch. Provide meaningful text explaining why the user received an SMS (e.g., ""We tried to send you an MMS, but it couldn't be delivered. View content here: [link]""). - Sinch typically hosts the MMS content and provides a link in the fallback SMS (unless
disable-fallback-sms-link
istrue
). Confirm this behavior and link validity/expiration with Sinch docs. - Consider the user experience for fallback scenarios.
- Understand the purpose and interaction of
- Content Constraints (Verify with Sinch Docs):
- Slides: Max 8 per message is typical, but verify this limit. Each slide must have
message-text
and/or one media element. - Media Types & Combinations: Cannot mix certain types on the same slide (e.g., image and video). Refer to the
sendmms
API docs for exact constraints and supported media types (image
,video
,audio
,pdf
,vcard
,calendar
). - File Size: Sinch has maximum file size limits for source media (often several MB, but verify for your account/region). Exceeding limits will cause failures.
- Subject Length: Max 80 characters typical, recommend <= 40 for better display on devices. Verify limit.
- Message Text Length: Typically max 5000 characters per slide's
message-text
. Verify limit.
- Slides: Max 8 per message is typical, but verify this limit. Each slide must have
- Media Hosting: The
Content-Length
header requirement is a critical and common pitfall. Test your media URLs usingcurl -I <your_media_url>
or similar tools to ensure the header is present and correct. If using a CDN, check its configuration regarding this header, especially ifTransfer-Encoding: chunked
is used.