Frequently Asked Questions
Create a RedwoodJS service to handle the messaging logic, integrate the MessageBird Node.js SDK, and expose the service through a GraphQL mutation. This allows your application to send SMS messages programmatically via the MessageBird API.
MessageBird acts as the third-party SMS gateway provider. The RedwoodJS application integrates with MessageBird's API using their Node.js SDK, allowing you to send SMS messages directly from your RedwoodJS application.
RedwoodJS offers a full-stack, serverless-friendly framework with built-in GraphQL and Prisma, simplifying development and deployment. Its structured approach promotes code organization and maintainability for campaign management.
Set a `MESSAGEBIRD_DEFAULT_ORIGINATOR` environment variable if you want a consistent sender ID for most campaigns. This simplifies the API call but can be overridden per campaign if needed. If not set, a generic default might be used, potentially affecting deliverability.
The basic implementation provides submission status. For detailed delivery reports (e.g., delivered, failed), configure MessageBird webhooks to receive real-time updates and store them in a database.
Install the MessageBird Node.js SDK, obtain your Live API Key from the MessageBird dashboard, and store it securely in a `.env` file in your project root. Never commit API keys directly into your code.
The core technologies include RedwoodJS, Node.js, MessageBird, Prisma (ORM), GraphQL, and Jest (testing). This combination provides a robust and efficient platform for building and managing SMS campaigns.
Error handling ensures your application gracefully manages issues like invalid recipient numbers, network problems, or MessageBird API errors. Implement try-catch blocks, logging, and retry mechanisms in your RedwoodJS service.
Retry logic is useful for handling transient errors, such as temporary network issues or brief MessageBird service disruptions. Use a library like `async-retry` to manage retries with exponential backoff.
Be aware of the 160-character limit for standard SMS. Longer messages are split (concatenated), impacting cost. Inform users of potential extra charges. Unicode (emoji) messages have a 70-character limit.
Use the E.164 format (+[country code][number]) for maximum compatibility, especially with international numbers. Consider using a library like `libphonenumber-js` for validation and normalization.
Storing campaign information in a database using Prisma allows you to track campaign history, monitor status (submitted, failed, etc.), and analyze campaign performance over time.
Use Redwood's authentication (e.g., `requireAuth`, `@requireAuth`), validate and sanitize user inputs, protect your MessageBird API key, and implement rate limiting to prevent abuse.
Alphanumeric sender IDs are supported in many countries but not all. Check MessageBird's documentation for country-specific regulations. In some regions (e.g., US/Canada), pre-registered numbers are required.
Adhere to MessageBird's best practices, including using registered sender IDs, handling opt-outs correctly, ensuring valid recipient numbers, and monitoring delivery reports via webhooks.
Build RedwoodJS Marketing Campaigns with MessageBird and Node.js
This guide provides a comprehensive, step-by-step walkthrough for building a feature within a RedwoodJS application to send marketing campaign messages via the MessageBird API using Node.js on the backend. We'll cover everything from initial project setup to deployment and verification.
By the end of this tutorial, you will have a RedwoodJS application with a GraphQL API endpoint capable of accepting campaign details (message content, recipient list) and utilizing the MessageBird SDK to dispatch SMS messages. This solves the common need for applications to programmatically send bulk or targeted SMS campaigns for marketing or notifications.
Project Overview and Goals
We aim to create a robust system within a RedwoodJS application that enables sending SMS marketing messages through MessageBird.
Key Goals:
Technologies Used:
System Architecture:
Prerequisites:
Expected Outcome:
A functional RedwoodJS application endpoint that can receive recipient numbers and a message, send SMS messages via MessageBird, and provide feedback on the operation's success or failure.
1. Setting up the Project
Let's start by creating a new RedwoodJS application and configuring the necessary environment.
Create RedwoodJS App: Open your terminal and run the RedwoodJS create command:
Follow the prompts (choosing JavaScript or TypeScript). For this guide, we'll assume JavaScript, but the steps are very similar for TypeScript.
Navigate to Project Directory:
Install MessageBird SDK: Install the MessageBird Node.js SDK specifically in the
api
workspace.Environment Variables: RedwoodJS uses
.env
files for environment variables. The.env.defaults
file is committed to git and holds default (non-sensitive) values. The.env
file (which should be in your.gitignore
) holds sensitive keys.Create the
.env
file in the project root:Add your MessageBird API Key and optionally a default originator to
.env
. We'll retrieve the API key in Section 4.It's good practice to add placeholders to
.env.defaults
so others know what's needed:Ensure
.env
is listed in your root.gitignore
file (Redwood typically adds this by default). TheMESSAGEBIRD_API_KEY
is your secret credential. TheMESSAGEBIRD_DEFAULT_ORIGINATOR
is the default sender ID or number if not provided in the request (see Section 4.3).Project Structure: RedwoodJS has a specific structure:
api/
: Backend code (GraphQL API, services, database schema).web/
: Frontend React code.scripts/
: Utility scripts.Our primary focus will be within the
api/
directory, specificallyapi/src/graphql
,api/src/services
, and potentiallyapi/db
. This structure separates concerns, making the application easier to manage.2. Implementing Core Functionality (Service Layer)
The core logic for interacting with MessageBird will reside in a RedwoodJS service. Services are where your business logic lives on the API side.
Generate Service: Use the RedwoodJS CLI to generate a service file for handling marketing campaigns.
This creates
api/src/services/marketingCampaigns/marketingCampaigns.js
(and related files like tests).Implement Sending Logic: Open
api/src/services/marketingCampaigns/marketingCampaigns.js
and add the logic to send messages.Why this approach?
try...catch
for robustness and provides informative error messages based on the SDK's potential error structure.3. Building the API Layer (GraphQL)
Now, expose the service function via a GraphQL mutation.
Define GraphQL Schema (SDL): Create/edit the GraphQL schema definition file for marketing campaigns.
Open
api/src/graphql/marketingCampaigns.sdl.js
and define the input type and mutation.Explanation:
SendCampaignInput
: Defines the structure of the data needed to call the mutation. Using input types keeps mutations clean.CampaignStatus
: Defines the structure of the response returned by the mutation.sendMarketingCampaign
: The mutation itself, linking to thesendMarketingCampaign
function in our service (Redwood maps this automatically by name convention). It takes the input and returns the status.@skipAuth
/@requireAuth
: Redwood's directive for controlling access. Use@requireAuth
once you have authentication implemented.@skipAuth
makes it publicly accessible (use with caution in production).Testing the Endpoint (GraphQL Playground): RedwoodJS comes with a GraphQL Playground.
Start the development server:
Navigate to
http://localhost:8910/graphql
.Use the following mutation (replace placeholders):
Execute the mutation. You should see a response like:
Or an error response if something went wrong:
4. Integrating with MessageBird (Configuration Details)
Ensuring the MessageBird SDK is correctly configured is crucial.
Obtaining the API Key:
Storing the API Key Securely:
As done in Step 1.4, paste the copied Live API Key into your
.env
file in the project root:Never commit your
.env
file or your API key directly into your code or version control (Git). Redwood's default.gitignore
should already include.env
.Understanding Environment Variables:
MESSAGEBIRD_API_KEY
: (Required) This is your secret credential for authenticating with the MessageBird API. The SDK (require('messagebird').initClient()
) automatically looks for this environment variable. Format: A string likelive_xxxxxxxxxxxxxxxxxxxx
. Obtain from: MessageBird Dashboard > Developers > API access.MESSAGEBIRD_DEFAULT_ORIGINATOR
: (Optional) You can set a default sender ID or phone number here if you don't want to specify it in every API call. If not set here and not provided in the mutation input, a generic default like ""Campaign"" might be used, which could impact deliverability. Format: A string (e.g., ""MyCompany"", ""+15551234567""). Obtain/Configure in: MessageBird Dashboard > Numbers or Sender IDs.Fallback Mechanisms: The current code doesn't explicitly implement complex fallback mechanisms for MessageBird outages. For critical systems, consider:
5. Error Handling, Logging, and Retry Mechanisms
Robust applications handle failures gracefully.
Error Handling Strategy:
try...catch
). Log detailed errors usinglogger.error()
. Return structured error information or throw specific GraphQL errors (UserInputError
,AuthenticationError
, etc.) for the API layer. The current implementation returns a structured error within theCampaignStatus
object.CampaignStatus
), that object is returned in thedata
field. If the service throws an error, it appears in theerrors
field of the GraphQL response.error.errors
(an array) for specific API validation issues (e.g., invalid recipient number, insufficient balance). Log these details. The current error handling attempts to extract the first error description.Logging:
pino
for logging. Uselogger.info()
,logger.warn()
,logger.error()
, etc., within your service.api/src/lib/logger.js
can be customized.Retry Mechanisms (Basic Example): For transient network issues or temporary MessageBird problems, a simple retry can help. You can use libraries like
async-retry
or implement a basic loop.Install
async-retry
:Modify the service function:
Testing Errors:
MESSAGEBIRD_API_KEY
in.env
to test authentication errors (and thebail
condition).6. Creating a Database Schema (Optional)
Storing campaign information can be useful for tracking history and status.
Define Prisma Schema: Open
api/db/schema.prisma
and add aCampaign
model.Campaign
. If linked to aUser
, it would be a one-to-many relationship (one User can have many Campaigns).Database Migration: Apply the schema changes to your database.
Enter a name for the migration when prompted (e.g.,
add campaign model
). This creates/updates your database tables.Update Service to Save Campaign: Modify the
sendMarketingCampaign
service to create aCampaign
record.db
object is the Prisma client instance, used for all database operations. This approach ensures campaign attempts are logged even if the MessageBird call fails.7. Adding Security Features
Security is paramount, especially when dealing with APIs and user data.
Input Validation & Sanitization:
+
followed by country code and number). You might add a regex check or use a library (likelibphonenumber-js
) for stricter validation.Authentication & Authorization:
requireAuth()
in the service (marketingCampaigns.js
) once you have RedwoodJS authentication set up (e.g.,yarn rw setup auth dbAuth
). This ensures only logged-in users can trigger campaigns.@requireAuth
to the GraphQL mutation definition (marketingCampaigns.sdl.js
) instead of@skipAuth
.context.currentUser.roles
).API Key Security:
.env
) and ensure.env
is in.gitignore
.Rate Limiting:
sendMarketingCampaign
mutation.yarn rw setup graphql-shield
) or a middleware approach (if using custom server file) to implement rate limiting (e.g., usingrate-limiter-flexible
). MessageBird also has its own API rate limits.Common Vulnerabilities:
userId
againstcontext.currentUser.id
in the service logic).8. Handling Special Cases
Real-world messaging involves nuances.
Phone Number Formatting (E.164):
+14155551234
). While it might correctly interpret local formats for some regions, relying on E.164 is safer for international delivery.libphonenumber-js
.Character Limits & Encoding:
result.recipients.totalSentCount
vsresult.recipients.totalCount
) might give clues, and webhooks provide more detail.Opt-Out Handling / Compliance:
Sender ID (Originator):
Delivery Status (Webhooks - Advanced):
delivered
,failed
,expired
arrive later.yarn rw g function messageStatus
). This function needs to handle POST requests from MessageBird, validate them, and update your database (e.g., update theCampaign
status).