simple-sms-sender
Version:
Simple SMS sender to multiple recipients using Twilio
138 lines (137 loc) • 4.26 kB
JavaScript
// src/SmsSender.ts
import twilio from "twilio";
var SmsSender = class {
/** Twilio Account SID */
accountSid;
/** Twilio client instance */
client;
/** Sender's phone number */
fromNumber;
/** Logger for logging messages and errors */
logger;
/** Twilio SID */
sid;
/** Twilio secret */
secret;
/**
* Creates an instance of SmsSender.
* @param accountSid - Twilio Account SID.
* @param fromNumber - Sender's phone number.
* @param logger - Logger for logging messages and errors.
* @param sid - Twilio SID.
* @param secret - Twilio secret.
*/
constructor({
accountSid,
fromNumber,
logger,
sid,
secret
}) {
this.accountSid = accountSid;
this.logger = logger || {
error: console.error.bind(console),
info: console.log.bind(console)
};
this.fromNumber = fromNumber;
this.sid = sid;
this.secret = secret;
this.client = twilio(this.sid, this.secret, {
accountSid: this.accountSid
});
}
/**
* Sends an SMS message to a list of recipients.
* @param body - The content of the SMS message.
* @param recipients - Array of recipient phone numbers.
* @param scheduledTime - Optional ISO 8601 formatted date/time to schedule the message.
* @throws Will throw an error if the body or recipients are empty.
* @returns A promise that resolves to an array of sent message objects.
*/
async sendSms({ body, recipients, scheduledTime }) {
if (!body || body.length === 0) {
throw new Error("No body to send SMS");
}
if (!recipients || recipients.length === 0) {
throw new Error("No recipients to send SMS");
}
if (scheduledTime) {
this.validateScheduledTime(scheduledTime);
}
const sendSmsToNumber = async (phoneNumber) => {
const to = phoneNumber?.trim();
if (!to) {
this.logger.error("Not a valid phone number to send SMS");
return;
}
this.logger.info(`Trying to send SMS to number ${phoneNumber}`);
try {
const message = await this.client.messages.create({
body,
to,
from: this.fromNumber,
...scheduledTime && { sendAt: new Date(scheduledTime) }
});
const { errorCode, errorMessage, status } = message;
if (errorCode) {
this.logger.error(
`There was an error sending SMS to number ${phoneNumber} (${errorCode} - ${errorMessage})`
);
} else {
this.logger.info(
`Sent SMS to number ${phoneNumber} successful (status ${status})`
);
}
return message;
} catch (error) {
this.logger.error(
`Could not send SMS to number '${phoneNumber}'`,
error
);
}
return;
};
return Promise.all(recipients.map(sendSmsToNumber));
}
/**
* Sends multiple SMS messages.
* @param messages - Array of messages to send.
* @returns A promise that resolves to an array of sent message objects.
*/
async sendMultipleSms(messages) {
return Promise.all(messages.map((message) => this.sendSms(message)));
}
/**
* Validates the scheduled time format and ensures it's in the future.
* @param scheduledTime - ISO 8601 formatted date/time string.
* @throws Will throw an error if the format is invalid or time is in the past.
*/
validateScheduledTime(scheduledTime) {
try {
const scheduledDate = new Date(scheduledTime);
if (isNaN(scheduledDate.getTime())) {
throw new Error("Invalid date format");
}
const now = /* @__PURE__ */ new Date();
if (scheduledDate <= now) {
throw new Error("Scheduled time must be in the future");
}
const maxFutureDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1e3);
if (scheduledDate > maxFutureDate) {
throw new Error(
"Scheduled time cannot be more than 7 days in the future"
);
}
} catch (error) {
if (error instanceof Error) {
throw new Error(`Invalid scheduledTime: ${error.message}`);
}
throw new Error(
"Invalid scheduledTime format. Please use ISO 8601 format (e.g., 2024-01-01T12:00:00Z)"
);
}
}
};
export {
SmsSender
};