Unified messaging library for Email, SMS, and Voice with multiple provider support
npm install parrot-messenger- What's New
- Features
- Prerequisites
- Installing
- Local Development
- Initialization
- Settings
- API
- Templates
- API Reference
#### Breaking Changes
- AWS SES Configuration: The AWS SES transport configuration has changed. The auth field now only accepts region, accessKeyId, and secretAccessKey properties. Additional AWS SDK configuration options are no longer supported.
Before (v1.x):
``typescript`
{
name: 'ses',
settings: {
auth: {
region: 'us-east-1',
credentials: { / ... / },
endpoint: 'https://custom-endpoint',
maxRetries: 3
// Other AWS SDK options...
}
}
}
`
After (v2.0.0):
typescript`
{
name: 'ses',
settings: {
auth: {
region: 'us-east-1',
accessKeyId: 'your-access-key',
secretAccessKey: 'your-secret-key'
}
}
}
#### New Features
- Chat Platform Support:
- Added Slack integration (bot tokens and webhooks)
- Added Telegram bot support with inline keyboards
- New chat transport class for messaging platformsany
- SMS Providers:
- Added Telnyx SMS support
- Added AWS SNS SMS support
- Enhanced Security:
- Fixed AWS credentials global pollution issue
- Added input validation for email addresses and phone numbers
- Implemented HTML sanitization to prevent XSS attacks
- Fixed TwiML injection vulnerability
- Better Error Handling:
- Added custom error types for better debugging
- Improved error messages with more context
- Added validation errors with clear messages
- Improved Type Safety:
- Reduced usage of types
- Better TypeScript support throughout the codebase
- Performance Enhancements:
- Transport clients are now properly managed
- Better resource utilization
- Testing: Achieved 97% test coverage
- CI/CD:
- Migrated from CircleCI to GitHub Actions
- Added Prettier formatting checks to CI
- Enforced 97% coverage thresholds
Parrot Messenger is a messaging library that can normalize the APIs for different messaging transports.
In its current iteration it supports 4 types of transport classes:
- Email
- SMS
- Call
- Chat
- AWS SES
- Mailchimp (Mandrill)
- Mailgun
- Sendgrid
- SMTP
- Twilio
- Telnyx
- AWS SNS
- Twilio
- Slack (Bot & Webhooks)
- Telegram
- Node.js 18+ or higher
- npm (comes with Node.js)
Using npm:
`bash`
$ npm install parrot-messenger
1. Clone the repository
`bash`
git clone https://github.com/BlackstoneStudio/Parrot-Messenger.git
cd Parrot-Messenger
2. Install dependencies
`bash`
npm install
3. Set up environment variables
`bash`
cp .env.example .env
.env
Edit and add your service credentials for testing.
- Build the project
`bash`
npm run build # Build TypeScript to JavaScript
npm run clean # Clean build artifacts
npm run dev # Build in watch mode for development
- Run tests
`bash`
npm test # Run all tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage report
npm run test:debug # Debug tests with Node inspector
- Code quality
`bash`
npm run lint # Check code with ESLint
npm run lint:fix # Auto-fix ESLint issues
npm run typecheck # Run TypeScript type checking
npm run format # Format code with Prettier
npm run format:check # Check code formatting
- Documentation
`bash`
npm run docs # Generate API documentation
npm run docs:watch # Generate docs in watch mode
- Release
`bash`
npm run release # Create a release (CI only)
npm run release:dry-run # Preview release changes
This project uses modern development tools:
- Prettier - Code formatting
- ESLint - Code linting with TypeScript support
- Husky - Git hooks for pre-commit checks
- lint-staged - Run linters on staged files
- TypeDoc - API documentation generation
- semantic-release - Automated versioning and releases
The project includes VS Code configuration for optimal development experience:
- Debugging - Launch configurations for debugging tests and TypeScript code
- Auto-formatting - Format on save with Prettier
- ESLint integration - Real-time linting feedback
- Recommended extensions - Suggested extensions for the best experience
To use: Open the project in VS Code and install recommended extensions when prompted.
``
parrot-messenger/
├── src/ # TypeScript source files
│ ├── transports/ # Transport implementations
│ │ ├── aws/ # AWS SES and SNS
│ │ ├── telnyx/ # Telnyx SMS
│ │ └── twilio/ # Twilio SMS and Call
│ ├── templates/ # Template engine
│ ├── constants/ # Constants (voices, etc.)
│ ├── errors.ts # Custom error types
│ ├── validation.ts # Input validation
│ └── send.ts # Core send logic
├── test/ # Test files
├── examples/ # Usage examples
├── dist/ # Compiled JavaScript (generated)
└── package.json # Project configuration
The project maintains 100% code coverage. When adding new features:
1. Write tests first (TDD approach recommended)
2. Ensure all tests pass: npm testnpm test -- --coverage
3. Check coverage: npm run lint
4. Fix any linting issues:
We welcome contributions! Please see our CONTRIBUTING.md file for detailed guidelines, including:
- Commit message format (following Blackstone Code Standards)
- Development workflow
- Testing requirements
- Code style guidelines
- Pull request process
Quick Start:
1. Fork the repository
2. Create a feature branch following our naming convention
3. Make your changes and add tests
4. Follow our commit message format: TYPE (Issue) Brief summary
5. Ensure all tests pass and maintain code coverage
6. Create a Pull Request
- Use console.log or debugger statements during developmentnpm test path/to/test.spec.ts
- Run tests for specific files:
- Use VS Code's built-in debugger with the following configuration:
`json`
{
"type": "node",
"request": "launch",
"name": "Jest Debug",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--runInBand"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}
Parrot needs to be initialized with the transports that it will be using before being used.
`js
// ES6
import Parrot from 'parrot-messenger';
// CommonJS
const { Parrot } = require('parrot-messenger');
const parrot = new Parrot({
transports: [
// List of transports settings enabled
mailgun,
mailchimp,
ses,
sendgrid,
twilioSMS,
twilioCall,
smtp,
slack,
telegram,
],
});
`
The parrot instance receives an array of transports with the settings for each transport. Each transport will have slightly different settings, particularly around the authentication for each. Example configurations are available in the examples.js file.
Each transport has a defaults object where you can define default parameters for all messages generated by that transport. So for example you can define a default from value for every message.
This is a sample object for AWS SES transport along with its default values:
`js`
const ses = {
name: 'ses',
settings: {
auth: {
region: '',
credentials: {
secretAccessKey: '',
accessKeyId: '',
},
},
defaults: {
from: 'me@parrotmessenger.com',
},
},
};
For Telnyx SMS transport:
`js`
const telnyxSMS = {
name: 'telnyxSMS',
settings: {
auth: {
apiKey: 'YOUR_TELNYX_API_KEY',
},
defaults: {
from: '+15551234567', // Your Telnyx phone number
},
},
};
For AWS SNS SMS transport:
`js`
const sns = {
name: 'sns',
settings: {
auth: {
secretAccessKey: 'YOUR_SECRET_ACCESS_KEY',
accessKeyId: 'YOUR_ACCESS_KEY_ID',
region: 'us-east-1',
},
smsType: 'Transactional', // or 'Promotional'
defaults: {
from: 'YourApp', // SMS Sender ID (not supported in all regions)
},
},
};
For Slack chat transport:
`js`
const slack = {
name: 'slack',
settings: {
auth: {
token: 'xoxb-your-bot-token', // Bot token
// OR
webhook: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL',
},
defaultChannel: '#general',
defaults: {},
},
};
For Telegram chat transport:
`js`
const telegram = {
name: 'telegram',
settings: {
auth: {
botToken: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
},
defaultChatId: '123456789', // Default chat/channel ID
parseMode: 'HTML', // or 'Markdown', 'MarkdownV2'
defaults: {},
},
};
Parrot Messenger works with a simple send service and a templating, here we'll describe the usage for the send method.
The send method receives 2 parameters, both being objects.
The first parameter is the parameters for the object that we want to send and the second one is the settings for the transport we want to use.
Example API call:
`js
const email = {
to: 'john@doe.com',
subject: 'Sample Message',
html: 'Hey Joe, nice talking to you!',
};
const transport = {
class: 'email',
name: 'ses',
};
parrot.send(email, transport);
`
Example Chat message:
`js
// Slack example
const slackMessage = {
to: '#announcements', // Channel, user ID, or conversation ID
subject: '🚀 New Feature Released',
html: 'Feature X is now available! Check it out here.',
};
parrot.send(slackMessage, { name: 'slack' });
// Telegram example
const telegramMessage = {
to: '@yourchannel', // Chat ID or @channelname
text: 'Hello from Parrot Messenger! 🦜',
attachments: [{
inline_keyboard: [[
{ text: 'Learn More', url: 'https://example.com' },
{ text: 'Get Started', callback_data: 'start' },
]],
}],
};
parrot.send(telegramMessage, { name: 'telegram' });
`
We can also use and register templates when using Parrot Messenger, so we can pre-define a set of messages we will be using. We use a templating language (Handlebars) to replace values inside the template before being sent.
Example Template Registration & Usage
` Hey there {{name}}!!js
// Register a template, notice the ussage of {{name}}
// this value will be replaced
parrot.templates.register({
name: 'Sample Template',
html: '
});
const messageData = {
to: 'john@doe.com',
subject: 'Hey there!',
};
const transport = {
class: 'email',
name: 'ses',
};
// Send an email using this template
parrot.templates.send(
'Sample Template',
messageData,
// Sample Data for Template
{ name: 'User' },
// Transport Settings
// Available classes email, sms & call
// Available transports per Class:
// Email: 'ses', 'mailgun', 'mailchimp', 'sendgrid', 'smtp'
// SMS: 'twilioSMS', 'telnyxSMS', 'sns'
// Call: 'twilioCall'
transport,
);
`
If you need to get the HTML template from an API service prior to senting a template you can do this as well. Parrot Messenger will use Axios to make an API request and fetch the necessary data, and it can be mapped from the response.
Example Async Template
`js
// Register template
parrot.templates.register({
name: 'Async Template',
// Request is a standard Axios type object
// with an additional resolve parameter
// that resolves the response of the object
// API reference for Axios:
// https://github.com/axios/axios#axios-api
request: {
method: 'GET',
url: 'https://reqres.in/api/unknown/2',
data: {},
headers: {},
// Path to string we want to use in the request's response
resolve: 'support.text',
},
});
const messageData = {
to: 'john@doe.com',
subject: 'Hey there!',
};
const transport = {
class: 'email',
name: 'ses',
};
// Send an email using this template
parrot.templates.send(
'Async Template',
messageData,
// Sample Data for Template
{ name: 'User' },
// Transport Settings
transport,
);
`
Parrot Messenger is written in TypeScript and provides full type definitions out of the box.
`typescript`
import Parrot, { Envelope, Transport } from 'parrot-messenger';
#### Envelope
The message object that all transports accept:
`typescript`
interface Envelope {
from?: string; // Sender address/number
to?: string; // Recipient address/number
subject?: string; // Email subject (required for email)
html?: string; // HTML content
text?: string; // Plain text content
voice?: string; // Voice selection for calls (see Voices section)
attachments?: Attachment[]; // File attachments
}
#### Transport Configuration
`typescript`
interface Transport {
name: TransportName;
class: 'email' | 'sms' | 'call';
settings: TransportSettings;
}
#### AWS SES
`typescript`
interface AWSSESConfig {
auth: {
region: string;
accessKeyId: string;
secretAccessKey: string;
};
defaults?: Envelope;
}
#### SendGrid
`typescript`
interface SendgridConfig {
auth: {
apiKey: string; // Must start with 'SG.'
};
defaults?: Envelope;
}
#### Mailgun
`typescript`
interface MailgunConfig {
auth: {
apiKey: string;
domain: string; // e.g., 'mg.yourdomain.com'
};
defaults?: Envelope;
}
#### Mailchimp (Mandrill)
`typescript`
interface MailchimpConfig {
auth: {
apiKey: string;
};
defaults?: Envelope;
}
#### SMTP
`typescript`
interface SMTPConfig {
auth: {
host: string;
port: number;
secure: boolean;
auth: {
user: string;
pass: string;
};
};
defaults?: Envelope;
}
#### Twilio SMS
`typescript`
interface TwilioSMSConfig {
auth: {
sid: string; // Account SID
token: string; // Auth token
};
defaults?: Envelope;
}
#### AWS SNS
`typescript`
interface AWSSNSConfig {
auth: {
region: string;
accessKeyId: string;
secretAccessKey: string;
};
smsType?: 'Transactional' | 'Promotional';
defaults?: Envelope;
}
#### Telnyx
`typescript`
interface TelnyxConfig {
auth: {
apiKey: string;
};
defaults?: Envelope;
}
#### Twilio Call
`typescript`
interface TwilioCallConfig {
auth: {
sid: string; // Account SID
token: string; // Auth token
};
defaults?: Envelope;
}
#### Slack
`typescript`
interface SlackConfig {
auth: {
token?: string; // Bot token (xoxb-...)
webhook?: string; // Webhook URL for simpler integration
};
defaultChannel?: string;
defaults?: Envelope;
}
#### Telegram
`typescript`
interface TelegramConfig {
auth: {
botToken: string; // Bot token from @BotFather
};
defaultChatId?: string | number;
parseMode?: 'HTML' | 'Markdown' | 'MarkdownV2';
defaults?: Envelope;
}
Parrot Messenger provides custom error types for better error handling:
`typescript
// Base error class
class ParrotError extends Error {
constructor(message: string, details?: any);
}
// Thrown when input validation fails
class ValidationError extends ParrotError {
constructor(message: string, field?: string);
}
// Thrown when a transport operation fails
class TransportError extends ParrotError {
constructor(message: string, transport?: string, originalError?: Error);
}
// Thrown when template processing fails
class TemplateError extends ParrotError {
constructor(message: string, templateName?: string);
}
// Thrown when configuration is invalid
class ConfigurationError extends ParrotError {
constructor(message: string, config?: any);
}
`
`typescript
import { send, ValidationError, TransportError } from 'parrot-messenger';
try {
await send(message, transports);
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid input:', error.message);
} else if (error instanceof TransportError) {
console.error('Transport failed:', error.message);
// Access original error: error.originalError
} else {
console.error('Unexpected error:', error);
}
}
`
Available voices for text-to-speech in calls:
`typescript
import { voices } from 'parrot-messenger';
// Example voices:
voices.Salli; // English (US)
voices.Amy; // English (British)
voices.Conchita; // Spanish (Castilian)
voices.Mizuki; // Japanese
// ... and many more
// Usage in envelope:
const message: Envelope = {
from: '+1234567890',
to: '+0987654321',
html: '
Hello!
',$3
When sending messages, you can filter which transports to use:
`typescript
// Use specific transport by name
await send(message, transports, { name: 'smtp' });// Use all transports of a specific class
await send(message, transports, { class: 'email' });
// Use specific transport with both name and class
await send(message, transports, { name: 'smtp', class: 'email' });
// Use multiple transports
await send(message, transports, [{ name: 'smtp' }, { name: 'ses' }]);
`$3
- Email addresses: Must be valid RFC-compliant email addresses
- Phone numbers: Must be valid E.164 format (e.g., +1234567890)
- Required fields:
-
to: Always required
- from: Always required
- subject: Required for email only
- html or text`: At least one is requiredBlackstone Studio is a custom software development company that specializes in AI-powered digital transformation solutions. We help you harness the power of artificial intelligence to build innovative solutions, accelerating your business's digital transformation journey.
- Custom Software Development
- Staff Augmentation
- Dedicated Teams
- Generative AI Development
- Mobile Development
- Web Development
- Software Testing
- Software Integrations
- No-Code Development
- Maintenance and Support
We pride ourselves on understanding each client's unique business model and creating solutions that complement their strategic vision. With our AI-centric approach to solving business challenges and flexible, adaptable development methodology, we build lasting partnerships that go beyond just software development. We serve diverse industries including retail, financial services, healthcare, real estate, and technology.
- Node.js - Runtime environment
- TypeScript - Type-safe JavaScript
- Jest - Testing framework with 100% code coverage
- Handlebars - Template engine
- Nodemailer - Email sending
- AWS SDK - AWS SES and SNS integration
- Twilio - SMS and voice calls
- GitHub Actions - CI/CD pipeline
Contributions, issues and feature requests are welcome!
You can also suggest a new feature by creating an Issue. Please wait for confirmation before working on it.
Copyright © 2025 Blackstone Studio.
This project is MIT licensed.