Frequently Asked Questions
Configure a Flow in your MessageBird Dashboard under the "Numbers" section. Select "Create Custom Flow," choose "SMS" as the trigger, and then "Forward to URL" as the next step. Set the method to POST and enter your application's public webhook URL (e.g., 'https://your-app.com/webhook'). For development, use ngrok or localtunnel to create a public URL and append '/webhook'.
MessageBird is the communication platform providing the APIs for sending and receiving SMS messages, as well as managing virtual mobile numbers (VMNs). It acts as the bridge between your application and the mobile network, allowing you to send bulk messages and receive user replies via webhooks.
The immediate '200 OK' response to MessageBird's webhook POST request acknowledges receipt and prevents MessageBird from retrying the delivery due to potential timeouts. The actual SMS confirmations to users are handled asynchronously afterwards by a separate function, ensuring MessageBird doesn't retry the webhook unnecessarily.
Always use a Live API key for production environments where you're sending real SMS messages. Test API keys are strictly for development and testing and shouldn't be used for actual campaigns due to rate limits and potential data inconsistencies.
For initial development, you can test the send functionality by logging the outgoing messages instead of actually sending them via the MessageBird API. For more realistic testing, create test accounts within MessageBird with dedicated virtual numbers to avoid sending unexpected SMS to real users during development.
The MessageBird API has a limit of 50 recipients per API call. The application code iterates through the subscriber list and sends messages in batches of 50 using a loop and array slicing to adhere to this limit. It's crucial to implement this batching to avoid errors from MessageBird.
The MongoDB database uses the subscribers collection. Each document stores the subscriber's number (E.164 format), subscribed status (boolean), subscribedAt timestamp, and unsubscribedAt timestamp. A unique index on the number field ensures no duplicate numbers are stored.
Storing the admin password in plain text in the .env file is extremely insecure. For production, replace this with a proper authentication system like Passport.js, OAuth 2.0, or JWT, which should store password hashes securely and implement robust login flows.
Implement MessageBird Webhook Signature Verification to ensure that incoming webhook requests are genuinely from MessageBird and not malicious actors. This involves calculating a signature hash and comparing it to the one provided in the 'MessageBird-Signature' header.
Recommended deployment options include PaaS solutions like Heroku, Render, or Fly.io for ease of management, or IaaS like AWS EC2 or Google Compute Engine for more control. Serverless functions might be suitable for specific components but may not be ideal for the whole application due to webhook and long-running process needs.
Use a library like async-retry or a job queue system to handle temporary failures when sending messages. This ensures better reliability for your SMS campaign and reduces the chance of messages not reaching subscribers.
The application uses Winston for logging, configured to log in JSON format for easier parsing and analysis. Logs are written to 'error.log' for error messages and 'combined.log' for other log levels. In development, logs are also outputted to the console.
Implement secure admin authentication, improve the admin UI for better user experience, implement MessageBird webhook signature verification, add advanced messaging features like personalization and scheduling, implement robust retry mechanisms, and thorough testing are important next steps to consider.
Build Production-Ready SMS Marketing Campaigns with MessageBird, Node.js & Express
Learn how to build a complete SMS marketing campaign system using MessageBird API, Node.js, and Express. This comprehensive tutorial shows you how to create a production-ready application where users subscribe and unsubscribe via SMS while administrators broadcast marketing messages to opted-in subscribers. You'll implement webhook integration for two-way messaging, MongoDB database management, TCPA compliance features, and deployment best practices for scaling your SMS marketing campaigns.
This SMS campaign application solves the common business need to manage SMS marketing lists efficiently while adhering to opt-in/opt-out regulations and TCPA compliance requirements. Leverage MessageBird's programmable virtual mobile numbers (VMNs) and real-time webhooks to create a seamless two-way messaging experience for both subscribers and administrators, enabling automated subscription management and bulk message broadcasting.
Technologies Used:
.envfile.System Architecture:
Prerequisites:
By the end of this guide_ you'll have a functional SMS subscription management and broadcasting application ready for further customization and deployment. For related topics_ see our guides on E.164 phone number formatting and 10DLC SMS registration requirements for US businesses.
1. Set up the Node.js Project with MessageBird SDK
Initialize your Node.js project and install the necessary dependencies for your SMS marketing campaign application. This section covers project initialization_ dependency installation_ environment variable configuration_ and basic Express server setup with security middleware.
Create Project Directory: Open your terminal and create a new directory for the project_ then navigate into it.
Initialize npm: Create a
package.jsonfile to manage dependencies.Install Dependencies: Install Express for the web server_ the MessageBird SDK_ the MongoDB driver_
dotenvfor environment variables_ andwinstonfor logging. Modern Express versions include body parsing middleware_ sobody-parseris not strictly required as a separate dependency.express: Web framework (includes JSON and URL-encoded body parsing).messagebird: Official SDK for interacting with the MessageBird API.mongodb: Driver for connecting to and interacting with MongoDB.dotenv: Loads environment variables from.envintoprocess.env.winston: Robust logging library.express-rate-limit: Middleware for rate limiting requests (added in Security section).helmet: Middleware for setting secure HTTP headers (added in Security section).Create
.gitignore: Prevent sensitive files and unnecessary directories from being committed to version control. Create a file named.gitignorewith the following content:Create
.envFile: Create a file named.envin the project root to store sensitive configuration. Never commit this file to Git.MESSAGEBIRD_API_KEY: Obtain your Live API key from the MessageBird Dashboard (Developers → API access).MESSAGEBIRD_ORIGINATOR: This is the virtual mobile number (VMN) you purchased from MessageBird (in E.164 format_ e.g._+12025550156) or an approved alphanumeric sender ID (max 11 characters_ check country restrictions).MONGODB_URI: The connection string for your MongoDB database. Replace with your actual URI if using Atlas or a different setup.sms_campaignis the database name.PORT: The port your application will run on locally.ADMIN_PASSWORD: WARNING: This plain-text password is for demonstration purposes only. In a production environment_ you must replace this with a secure authentication mechanism (e.g._ hashed passwords with a proper login flow using libraries like Passport.js_ or OAuth).Basic
index.jsStructure: Create anindex.jsfile in the root directory. This will be the entry point of our application.This sets up the basic Express server, loads environment variables, initializes the MessageBird SDK and Winston logger, establishes the MongoDB connection, applies basic security middleware, and prepares the
subscriberscollection with a unique index on thenumberfield.2. Implement SMS Webhook Handler for Incoming Messages
Create a webhook endpoint to receive and process incoming SMS messages sent by users to your MessageBird virtual number. This enables two-way SMS messaging where users can text "SUBSCRIBE" to opt-in or "STOP" to opt-out from your marketing campaigns, with automatic confirmation messages and database updates.
Configure MessageBird Flow Builder:
MESSAGEBIRD_ORIGINATOR.</>) next to the number. If no flow exists, click "Add flow".+button below it.POST.node index.js). Then, use ngrok or localtunnel:ngrok http 8080orlt --port 8080httpsforwarding URL provided (e.g.,https://randomstring.ngrok.ioorhttps://yoursubdomain.loca.lt)./webhookto this URL (e.g.,https://randomstring.ngrok.io/webhook). Paste this full URL into the Flow Builder step.https://your-app-domain.com/webhook).Create the Webhook Route (
/webhook): Add the following route handler insideindex.jswithin the// --- Routes ---section.This route handles incoming
POSTrequests from MessageBird. It parses the sender's number (originator) and the message text (payload), converts the text to lowercase, and performs database operations based on thesubscribeorstopkeywords. It uses theloggerfor detailed logging. It calls thesendConfirmationhelper function (which runs asynchronously) to send confirmation messages back to the user and responds to MessageBird with a200 OKimmediately to acknowledge receipt, explaining why this is done.3. Build the MessageBird API Integration for Bulk SMS Broadcasting
Create an admin interface to send bulk SMS marketing messages to all subscribed users. This section implements batch processing to handle large subscriber lists efficiently, with built-in error handling and delivery tracking. You'll build a password-protected web form for campaign management.
Create Admin Form Route (
GET /admin): This route displays the HTML form. Add this within the// --- Routes ---section inindex.js.Create Send Message Route (
POST /send): This route handles the form submission, verifies the password, fetches subscribers, and sends the message in batches. Add this within the// --- Routes ---section.This route first checks the admin password (again, stressing this is INSECURE). If valid, it fetches all subscribed numbers from MongoDB. It then iterates through the numbers in batches of 50 and sends the message using
await messagebird.messages.create(params);, leveraging the native Promise returned by recent SDK versions. Detailed logging usingloggeris included for batch success and failure.Test with
curl: Test the/sendendpoint usingcurl(replace placeholders):(Response: A success or error message from the server)
4. Integrate MessageBird SMS API with Node.js (Summary)
You've already integrated MessageBird in the previous steps. Here's a summary of the key MessageBird API integration points:
npm install messagebirdconst messagebird = require('messagebird')(process.env.MESSAGEBIRD_API_KEY);placed early inindex.js..env(MESSAGEBIRD_API_KEY=YOUR_LIVE_API_KEY) and load viadotenv. Obtain this from your MessageBird Dashboard → Developers → API access. Ensure it's a Live key for actual sending..env(MESSAGEBIRD_ORIGINATOR=YOUR_VMN_OR_SENDER_ID). This must be a number purchased/verified in your MessageBird account or an approved alphanumeric ID.await messagebird.messages.create(params)(for Promise-based handling) ormessagebird.messages.create(params, callback)(for callback style). Theparamsobject must includeoriginator,recipients(an array of numbers), andbody.MESSAGEBIRD_ORIGINATORnumber viaPOSTto your application's/webhookURL. The webhook handler parsesreq.body.originatorandreq.body.payload.5. Implement Error Handling, Logging, and SMS Retry Mechanisms
Production SMS applications need robust error handling and logging.
Logging Strategy: Integrate Winston for structured JSON logging to files (
error.log,combined.log) and optionally to the console in development.index.js.console.*calls withlogger.info,logger.warn, andlogger.error. Log errors with message and stack trace where applicable. Include contextual information (likeoriginator,batchNumber) in log calls.Error Handling:
try...catch: Wrap database operations and MessageBird API calls intry...catchblocks.originator,payload,message,password), returning appropriate HTTP status codes (400, 401).200 OKquickly to MessageBird.Retry Mechanisms (for Sending): MessageBird API calls might fail temporarily. Implement retries only for critical outgoing messages (like the main campaign send), not usually for webhook processing (to avoid duplicate actions).
Simple Manual Retry Example (Illustrative): The following demonstrates a basic retry loop within the
/sendroute's batch processing. For production, consider a more robust library likeasync-retry.Note: Implement retry logic carefully. Retrying non-idempotent operations can cause issues. Sending SMS is generally safe to retry if the initial attempt failed definitively.
6. Design MongoDB Schema for SMS Subscriber Management
Use MongoDB with a simple schema defined by the documents you insert for SMS subscription tracking.
Collection:
subscribersDocument Structure:
_id: Automatically generated by MongoDB.number: Phone number in E.164 format (Indexed, Unique).subscribed: Boolean indicating current subscription status.subscribedAt: Timestamp of the last subscription action.unsubscribedAt: Timestamp of the last unsubscription action (null if subscribed).Data Access: Handle via the
mongodbdriver'sMongoClient. Set upmongoClient,db, andsubscribersCollectioninindex.js.Key Operations:
subscribersCollection.findOne({ number: ... })(Used in webhook)subscribersCollection.insertOne({ ... })(Used for new subscribers)subscribersCollection.updateOne({ number: ... }, { $set: { ... } })(Used for re-subscribing or unsubscribing)subscribersCollection.find({ subscribed: true }, { projection: { ... } }).toArray()(Used in/send)subscribersCollection.countDocuments({ subscribed: true })(Used in/admin)Indexing: A unique index on the
numberfield (subscribersCollection.createIndex({ number: 1 }, { unique: true })) is crucial for performance and data integrity, ensuring you don't store duplicate numbers. Create this on application start.Migrations: For this simple schema, migrations aren't strictly necessary. For evolving schemas, tools like
migrate-mongocan manage database changes systematically.Sample Data (Manual Insertion via
mongosh):7. Add Security Features for SMS Marketing Applications
Security is paramount when handling user data and sending SMS messages.
originatorandpayloadexist. Trimpayload. Consider adding E.164 format validation fororiginator.messageis not empty. Validatepassword. Consider adding length limits or sanitization tomessage.express-rate-limit.Implementation: Add configuration in
index.jsbefore routes.helmet.app.use(helmet());added early inindex.js./sendis highly insecure. Replace this immediately in a production environment with a proper authentication system (e.g., Passport.js with username/hashed password stored securely, OAuth, JWT)..envanddotenv. Ensure the.envfile is never committed to version control (.gitignore).npm audit,npm update) to patch known vulnerabilities. Use tools like Snyk or Dependabot for automated scanning.8. Deploy Your SMS Campaign Application to Production
Deploy your Node.js SMS marketing application following these steps.
MESSAGEBIRD_API_KEY,MONGODB_URI,PORT, and crucially, replace the insecureADMIN_PASSWORDwith your secure authentication mechanism's configuration. Do not use a.envfile in production; use the hosting provider's mechanism for setting environment variables.NODE_ENV=production: This environment variable enables optimizations in Express and other libraries and disables development-only features (like verbose console logging in your setup).https://your-app-domain.com/webhook). Ensure this URL is accessible from the internet.9. SMS Marketing Compliance and Next Steps
You've successfully built a foundational SMS marketing campaign application using Node.js, Express, MongoDB, and MessageBird API. Users can subscribe and unsubscribe via SMS, and an administrator can broadcast messages to active subscribers.
Key achievements:
SUBSCRIBEandSTOPmessages.Next Steps:
Hello {name}, …) for targeted campaigns.async-retryor implement a background job queue (e.g., BullMQ, Kue) for handling message sending failures more reliably.