Frequently Asked Questions
You can send MMS messages with RedwoodJS by integrating with AWS Pinpoint and S3. This involves setting up AWS resources (IAM user, S3 bucket, Pinpoint number), installing the AWS SDK v3, configuring environment variables, implementing a RedwoodJS service function, and exposing the functionality via a GraphQL mutation. The service function interacts with the Pinpoint API to send messages, using S3 to store media attachments.
AWS Pinpoint is used for sending the actual MMS messages. Its `SendMediaMessage` API action, part of the SMS and Voice v2 API, handles message dispatch. Pinpoint integrates with S3 for media handling and requires specific IAM permissions for secure access. Note: Pinpoint's primary MMS support is for US and Canadian destinations.
MMS messages include media attachments (images, videos, etc.). An S3 bucket is used to store these media files, which AWS Pinpoint then accesses and includes when sending the MMS. The S3 bucket and your Pinpoint origination number *must* be in the same AWS region.
Toll-free numbers are often easiest for initial testing and development with Pinpoint. However, for production application-to-person (A2P) messaging in the US, 10DLC (10-digit long code) is the standard and generally recommended for better deliverability and compliance. Short codes require a more complex application process.
No, AWS Pinpoint cannot receive inbound MMS media (like images sent to your Pinpoint number). While it can typically receive inbound *text* (SMS) replies, if the number and Pinpoint are configured to do so, it does not support receiving media attachments in replies.
Create a dedicated IAM user or role with a least-privilege policy. This policy should grant `sms-voice:SendMediaMessage` permission for Pinpoint and `s3:GetObject` (and optionally `s3:ListBucket`) permission for your S3 bucket containing the media files. Restricting permissions enhances security.
The AWS SDK for JavaScript v3 is used with the specific client package `@aws-sdk/client-pinpoint-sms-voice-v2`. This provides the necessary functions and types to interact with the Pinpoint SMS and Voice v2 API. Install it with: `yarn add @aws-sdk/client-pinpoint-sms-voice-v2` within the `api` side of your redwood project.
AWS Pinpoint needs to access the media files stored in your S3 bucket to include them in the MMS message. For efficiency and to avoid cross-region data transfer costs, these resources must be in the same AWS region. This is a mandatory requirement for MMS sending.
Media URLs must be S3 URIs in the format `s3://YOUR_BUCKET_NAME/path/to/your/file.jpg`. Ensure your IAM user has `s3:GetObject` permission for the specified objects in the bucket. The bucket must be in the same region as your Pinpoint origination number.
Use a `try...catch` block in your service function. Catch errors from the AWS SDK, log details using `logger.error`, and re-throw a more generic error to the GraphQL layer. You can check for specific AWS error types (e.g., `ValidationException`) to refine handling.
The `MessageId` in the Pinpoint `SendMediaMessage` response only confirms that AWS Pinpoint has *accepted* the send request. It does *not* guarantee message delivery to the handset. Tracking delivery requires setting up event streaming (e.g., using SNS or Kinesis).
Use a retry mechanism (a simple loop or library like `async-retry`) to handle transient errors like network issues or throttling. Include exponential backoff and ensure you *only* retry on appropriate, transient errors. Avoid retrying on validation or permission errors.
Store AWS credentials securely in a `.env` file in the root of your RedwoodJS project. This file should *never* be committed to version control. Use environment variables like `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
The RedwoodJS service, typically named `mmsService` (or similar) and located at `api/src/services/mms/mms.ts`, encapsulates all logic for sending MMS messages using the AWS SDK and handling responses or errors. The service function is automatically linked to your GraphQL mutation if you follow Redwood naming conventions.
This guide provides a complete walkthrough for integrating AWS Pinpoint's MMS capabilities into a RedwoodJS application. We'll cover everything from setting up your AWS resources and RedwoodJS project to implementing the sending logic, handling errors, testing, and deployment. By the end, you'll have a functional service capable of sending text messages with media attachments (images, videos, etc.) via AWS.
Target Audience: Developers familiar with RedwoodJS and basic AWS concepts. Goal: Build a production-ready RedwoodJS service to send MMS messages using AWS Pinpoint and S3.
Project Overview and Goals
Sending rich media content like images or videos alongside text messages (MMS) can significantly enhance user engagement compared to standard SMS. However, integrating MMS sending requires specific cloud infrastructure setup and careful handling of media files.
This guide solves the problem of reliably sending MMS messages from a RedwoodJS backend by leveraging AWS services.
Specific Goals:
Technologies Involved:
SendMediaMessage
API action to dispatch MMS messages. Chosen for its scalability and integration with other AWS services. Note: Pinpoint MMS sending is primarily available for US and Canadian destinations.System Architecture:
(Note: This text-based diagram illustrates the flow. For complex systems, a visual diagram (e.g., using tools like draw.io, Lucidchart, or Mermaid) is recommended.)
Prerequisites:
Expected Outcome:
A RedwoodJS application with a GraphQL mutation
sendMms
that accepts a destination phone number, message body, and an array of S3 URIs for media files. Calling this mutation will trigger an MMS message send via AWS Pinpoint.1. Setting up AWS Resources
Before writing any RedwoodJS code, we need the necessary AWS infrastructure.
Step 1: Create an IAM User/Role for RedwoodJS Backend
It's crucial to follow the principle of least privilege. Create an IAM user (or role, if deploying to EC2/ECS/Lambda) specifically for your RedwoodJS application.
Navigate to the IAM console in your AWS account.
Go to ""Users"" and click ""Create user"".
Provide a username (e.g.,
redwoodjs-mms-app-user
).Choose ""Provide user access to the AWS Management Console"" - Optional. This is only necessary if a human needs to log into the AWS console with this user's credentials. It's not required for the application's programmatic access via access keys.
Select ""Attach policies directly"".
Click ""Create policy"".
Switch to the ""JSON"" editor.
Paste the following policy, replacing
YOUR_S3_BUCKET_NAME
andYOUR_AWS_REGION
:sms-voice:SendMediaMessage
: Allows sending MMS via the Pinpoint SMS/Voice v2 API.s3:GetObject
: Allows reading the media files from your designated S3 bucket. Pinpoint needs this to fetch the media.s3:ListBucket
: While not strictly required bySendMediaMessage
itself, it's often useful for debugging or listing objects if your app needs it. You can remove it if onlyGetObject
is needed. EnsureYOUR_S3_BUCKET_NAME
is correctly replaced.Click ""Next"".
Give the policy a name (e.g.,
RedwoodJSMMSSendingPolicy
).Click ""Create policy"".
Go back to the user creation tab, refresh the policy list, and select the
RedwoodJSMMSSendingPolicy
you just created.Click ""Next"".
Review and click ""Create user"".
Crucially: Navigate to the newly created user, go to the ""Security credentials"" tab, and under ""Access keys"", click ""Create access key"".
Select ""Application running outside AWS"" (or the appropriate option).
Click ""Next"". Add a description tag if desired.
Click ""Create access key"".
Immediately copy the ""Access key ID"" and ""Secret access key"". You won't be able to see the secret key again. Store these securely. We'll use them in our RedwoodJS environment variables later.
Step 2: Create an S3 Bucket for Media Files
Pinpoint needs access to your media files stored in S3.
your-company-mms-media-unique-id
). Remember this name.Step 3: Obtain an MMS-Capable Pinpoint Origination Identity
You need a phone number (Short Code, Toll-Free Number, or 10DLC for the US; Long Code or Short Code for Canada) registered in Pinpoint and enabled for MMS.
+12065550100
). This is yourOriginationIdentity
.2. Setting up the RedwoodJS Project
Now, let's configure our RedwoodJS application.
Step 1: Create or Use Existing RedwoodJS App
If you don't have one, create a new RedwoodJS project:
Step 2: Install AWS SDK v3
We need the specific client for the Pinpoint SMS and Voice v2 API.
Step 3: Configure Environment Variables
Store your AWS credentials and configuration securely. Create or edit the
.env
file in the root of your RedwoodJS project. Never commit this file to version control if it contains secrets. Use a.env.example
and.gitignore
.AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
: Credentials for the IAM user created earlier. The SDK will automatically pick these up.AWS_REGION
: Essential for the SDK to target the correct AWS region where your Pinpoint number and S3 bucket exist.PINPOINT_ORIGINATION_NUMBER
: The E.164 formatted phone number registered in Pinpoint that will send the MMS.S3_MMS_BUCKET_NAME
: The name of the S3 bucket created for media storage.Important: Ensure your root
.gitignore
file includes.env
.3. Implementing Core Functionality (RedwoodJS Service)
We'll create a RedwoodJS service to encapsulate the logic for sending MMS messages.
Step 1: Generate the Service
Use the RedwoodJS CLI to generate a service for MMS operations.
This creates
api/src/services/mms/mms.ts
andapi/src/services/mms/mms.test.ts
.Step 2: Implement the
sendMms
Service FunctionOpen
api/src/services/mms/mms.ts
and add the following code:PinpointSMSVoiceV2Client
is instantiated. It automatically finds credentials (via environment variables, EC2 instance profile, etc.) and the region (AWS_REGION
).sendMms
function takes the destination number, an optional array of S3 URIs (s3://bucket/object.ext
), and an optional message body..env
.SendMediaMessageCommandInput
object, mapping our arguments to the API parameters.OriginationIdentity
is set to our configured sending number.MediaUrls
expects an array of strings in the formats3://YOUR_BUCKET_NAME/path/to/your/file.jpg
. Pinpoint fetches these files.pinpointClient.send()
method dispatches the command to AWS.logger
.try...catch
block, logs the error, and re-throws it.MessageId
, which confirms AWS accepted the request, not that the message was delivered.4. Building a Complete API Layer (GraphQL Mutation)
Let's expose the
sendMms
service function through Redwood's GraphQL API.Step 1: Define the GraphQL Schema
Open or create
api/src/graphql/mms.sdl.ts
:MmsResponse
type to represent the data returned (primarily theMessageId
). Added a comment about potentially including other fields.sendMms
mutation within theMutation
type.destinationPhoneNumber
,mediaUrls
(an array of strings), andmessageBody
as arguments.!
denotes required fields.@requireAuth
ensures only authenticated users can call this mutation. Change to@skipAuth
if authentication is not needed for this specific action, but be cautious about potential abuse.Step 2: Link Service to GraphQL (Implicit)
RedwoodJS automatically maps GraphQL resolvers to service functions based on naming conventions. Since our mutation is named
sendMms
and our service file (api/src/services/mms/mms.ts
) exports a function namedsendMms
, Redwood handles the connection. No explicit resolver code is needed inapi/src/functions/graphql.ts
unless you need custom logic before or after calling the service.Step 3: Testing the Mutation
Ensure you have uploaded a test file (e.g.,
test.jpg
) to your S3 bucket (s3://YOUR_S3_BUCKET_NAME/test.jpg
). Make sure the IAM user hass3:GetObject
permission for this file.Start your RedwoodJS development server:
yarn rw dev
.Navigate to the GraphQL Playground, usually
http://localhost:8911/graphql
.If using
@requireAuth
, ensure you configure theAuthorization: Bearer <token>
header appropriately based on your auth setup.Execute the following mutation (replace placeholders):
Check the response in the Playground. You should see a
messageId
if successful.Check the recipient phone; the MMS message should arrive shortly.
Check the API server logs (
yarn rw dev
console output) for log messages from the service.Example cURL Request:
Example JSON Response:
5. Integrating with Necessary Third-Party Services (AWS)
This section summarizes the critical integration points covered in the setup sections.
.env
(AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
)..env
(AWS_REGION
).@aws-sdk/client-pinpoint-sms-voice-v2
in the RedwoodJS service.s3:GetObject
). The same AWS keys are used.s3://BUCKET_NAME/OBJECT_KEY
) in theMediaUrls
parameter of theSendMediaMessageCommand
.sms-voice:SendMediaMessage
ands3:GetObject
on the specific bucket.Fallback Mechanisms: AWS services are generally reliable, but for critical messaging:
6. Implementing Error Handling, Logging, and Retry Mechanisms
Robust applications need proper error handling.
Error Handling Strategy:
sendMms
service function includes atry...catch
block. It catches errors from the AWS SDK, logs detailed information (including the input parameters and the error itself), and then re-throws a generic error. This prevents leaking sensitive AWS error details directly to the client while still signaling failure.catch
block in the service to check for specific AWS error codes (e.g.,error.name === 'ValidationException'
) to provide more context or potentially trigger different actions (like alerting onAccessDeniedException
).Logging:
logger
(import { logger } from 'src/lib/logger'
).logger.info
: Used for successful operations or key steps (e.g., attempting send, successful send).logger.warn
: Used for potential issues that don't stop the process (e.g., missing MessageId in response).logger.error
: Used for critical failures (e.g., failed AWS SDK call, invalid S3 URL).commandInput
orresponse
) in the log objects.Retry Mechanisms:
Network issues or temporary AWS glitches can occur. Implementing retries can improve reliability.
retryOperation
helper is added.pinpointClient.send
call) and retry parameters.delayMs * Math.pow(backoffFactor, attempt - 1)
) to avoid overwhelming the service.isRetryable
) with a strong caveat that this check must be refined based on AWS documentation and testing to only retry genuinely transient errors. Do not retry on errors likeValidationException
orAccessDeniedException
.async-retry
offer more sophisticated features (jitter, custom retry conditions).Testing Error Scenarios:
ValidationException
,ThrottlingException
,AccessDeniedException
) and verify that your error handling and retry logic behave as expected.7. Database Schema and Data Layer
While not strictly required just to send an MMS, a real-world application would likely store information about sent messages.
Potential Schema (using Prisma in
schema.prisma
):Implementation:
schema.prisma
.yarn rw prisma migrate dev
to apply the changes to your database.sendMms
service function:MmsMessage
record in the database before callingpinpointClient.send()
, setting the status toPENDING
.pinpointClient.send()
call (or retry operation) is successful, update the record with theproviderMessageId
and set the status toSENT_TO_PROVIDER
.errorMessage
and set the status toFAILED
.