A Node.js library to send all kinds of transactional notifications.
-
Easy channel integration — Want to start sending
emails
|SMS
|pushes
|webpushes
|slack
? Do so in no time! -
Unique documentation — Don't look everywhere for the parameters you need to pass, just do it once. Switching provider becomes a no-brainer.
-
Multiple providers strategies — Want to use more than one provider? Use
fallback
andround-robin
strategies out of the box. -
Tools for local testing — Run a catcher locally to intercept all your notifications and display them in a web interface.
-
MIT license — Use it like you want.
$ yarn add notifme-sdk
import NotifmeSdk from 'notifme-sdk'
const notifmeSdk = new NotifmeSdk({}) // empty config = all providers are set to console.log
notifmeSdk
.send({sms: {from: '+15000000000', to: '+15000000001', text: 'Hello, how are you?'}})
.then(console.log)
✨ Congratulations, you should see the following lines in your console:
Notification Catcher is a web interface for viewing and testing notifications during development.
$ yarn add --dev notification-catcher
$ yarn run notification-catcher
import NotifmeSdk from 'notifme-sdk'
const notifmeSdk = new NotifmeSdk({
useNotificationCatcher: true // <= this sends all your notifications to the catcher running on port 1025
})
notifmeSdk
.send({sms: {from: '+15000000000', to: '+15000000001', text: 'Hello, how are you?'}})
.then(console.log)
😻 Open http://localhost:1080 on your favorite browser, you should see the notification:
If you have the Notification Catcher running on a custom port, domain, or you need to change any other connection setting, set the environment variable NOTIFME_CATCHER_OPTIONS
with your custom connection smtp url.
$ # Example
$ NOTIFME_CATCHER_OPTIONS=smtp://127.0.0.1:3025?ignoreTLS=true node your-script-using-notifme.js
new NotifmeSdk({
channels: ..., // Object
useNotificationCatcher: ... // boolean
})
Option name | Required | Type | Description |
---|---|---|---|
channels |
false |
Object |
Define providers (Array ) and multiProviderStrategy (string ) for each channel (email, sms, push, webpush, slack).See all details below: 2. Providers. |
useNotificationCatcher |
false |
boolean |
If true, all your notifications are sent to the catcher running on localhost:1025 (channels option will be completely ignored!) |
// Env: development
new NotifmeSdk({
useNotificationCatcher: true
})
// Env: production
new NotifmeSdk({
channels: {
email: {
// If "Provider1" fails, use "Provider2"
multiProviderStrategy: 'fallback',
providers: [{
type: 'Provider1',
// ...credentials
}, {
type: 'Provider2',
// ...credentials
}]
},
sms: {
// Use "Provider1" and "Provider2" in turns (and fallback if error)
multiProviderStrategy: 'roundrobin',
providers: [{
type: 'Provider1',
// ...credentials
}, {
type: 'Provider2',
// ...credentials
}]
}
}
})
If you want to use a HTTP proxy, set an environment variable NOTIFME_HTTP_PROXY
.
$ # Example
$ NOTIFME_HTTP_PROXY=http://127.0.0.1:8580 node your-script-using-notifme.js
Logger (for development)
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'logger'
}]
}
}
})
SMTP (can be used for almost all providers)
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'smtp',
host: 'smtp.example.com',
port: 465,
secure: true,
auth: {
user: 'xxxxx',
pass: 'xxxxx'
}
}]
}
}
})
Sendmail
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'sendmail',
sendmail: true,
newline: 'unix',
path: '/usr/sbin/sendmail'
}]
}
}
})
Mailgun
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'mailgun',
apiKey: 'xxxxx',
domainName: 'example.com'
}]
}
}
})
Mandrill
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'mandrill',
apiKey: 'xxxxx'
}]
}
}
})
Sendgrid
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'sendgrid',
apiKey: 'xxxxx'
}]
}
}
})
SES
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'ses',
region: 'xxxxx',
accessKeyId: 'xxxxx',
secretAccessKey: 'xxxxx',
sessionToken: 'xxxxx' // optional
}]
}
}
})
SparkPost
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'sparkpost',
apiKey: 'xxxxx'
}]
}
}
})
Custom (define your own)
new NotifmeSdk({
channels: {
email: {
providers: [{
type: 'custom',
id: 'my-custom-email-provider...',
send: async (request) => {
// Send email
return 'id...'
}
}]
}
}
})
request
being of the following type.
See all options: Email provider options
Logger (for development)
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'logger'
}]
}
}
})
46elks
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: '46elks',
apiUsername: 'xxxxx',
apiPassword: 'xxxxx'
}]
}
}
})
Callr
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'callr',
login: 'xxxxx',
password: 'xxxxx'
}]
}
}
})
Clickatell
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'clickatell',
apiKey: 'xxxxx' // One-way integration API key
}]
}
}
})
Infobip
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'infobip',
username: 'xxxxx',
password: 'xxxxx'
}]
}
}
})
Nexmo
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'nexmo',
apiKey: 'xxxxx',
apiSecret: 'xxxxx'
}]
}
}
})
OVH
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'ovh',
appKey: 'xxxxx',
appSecret: 'xxxxx',
consumerKey: 'xxxxx',
account: 'xxxxx',
host: 'xxxxx' // https://github.com/ovh/node-ovh/blob/master/lib/endpoints.js
}]
}
}
})
Plivo
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'plivo',
authId: 'xxxxx',
authToken: 'xxxxx'
}]
}
}
})
Twilio
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'twilio',
accountSid: 'xxxxx',
authToken: 'xxxxx'
}]
}
}
})
Custom (define your own)
new NotifmeSdk({
channels: {
sms: {
providers: [{
type: 'custom',
id: 'my-custom-sms-provider...',
send: async (request) => {
// Send SMS
return 'id...'
}
}]
}
}
})
request
being of the following type.
See all options: SMS provider options
Logger (for development)
new NotifmeSdk({
channels: {
voice: {
providers: [{
type: 'logger'
}]
}
}
})
Twilio
new NotifmeSdk({
channels: {
voice: {
providers: [{
type: 'twilio',
accountSid: 'xxxxx',
authToken: 'xxxxx'
}]
}
}
})
Custom (define your own)
new NotifmeSdk({
channels: {
voice: {
providers: [{
type: 'custom',
id: 'my-custom-voice-provider...',
send: async (request) => {
// Send Voice
return 'id...'
}
}]
}
}
})
request
being of the following type.
See all options: Voice provider options
Logger (for development)
new NotifmeSdk({
channels: {
push: {
providers: [{
type: 'logger'
}]
}
}
})
APN (Apple Push Notification)
new NotifmeSdk({
channels: {
push: {
providers: [{
type: 'apn',
token: {
key: './certs/key.p8',
keyId: 'xxxxx',
teamId: 'xxxxx'
}
}]
}
}
})
FCM (Firebase Cloud Messaging, previously called GCM, Google Cloud Messaging)
new NotifmeSdk({
channels: {
push: {
providers: [{
type: 'fcm',
id: 'xxxxx'
}]
}
}
})
WNS (Windows Push Notification)
new NotifmeSdk({
channels: {
push: {
providers: [{
type: 'wns',
clientId: 'xxxxx',
clientSecret: 'xxxxx',
notificationMethod: 'sendTileSquareBlock'
}]
}
}
})
ADM (Amazon Device Messaging)
new NotifmeSdk({
channels: {
push: {
providers: [{
type: 'adm',
clientId: 'xxxxx',
clientSecret: 'xxxxx'
}]
}
}
})
Custom (define your own)
new NotifmeSdk({
channels: {
push: {
providers: [{
type: 'custom',
id: 'my-custom-push-provider...',
send: async (request) => {
// Send push
return 'id...'
}
}]
}
}
})
request
being of the following type.
See all options: Push provider options
Logger (for development)
new NotifmeSdk({
channels: {
webpush: {
providers: [{
type: 'logger'
}]
}
}
})
GCM (Google Cloud Messaging) - uses W3C endpoints if possible
new NotifmeSdk({
channels: {
webpush: {
providers: [{
type: 'gcm',
gcmAPIKey: 'xxxxx',
vapidDetails: {
subject: 'mailto: [email protected]',
publicKey: 'xxxxx',
privateKey: 'xxxxx'
}
}]
}
}
})
Custom (define your own)
new NotifmeSdk({
channels: {
webpush: {
providers: [{
type: 'custom',
id: 'my-custom-webpush-provider...',
send: async (request) => {
// Send webpush
return 'id...'
}
}]
}
}
})
request
being of the following type.
See all options: Webpush provider options
Logger (for development)
new NotifmeSdk({
channels: {
slack: {
providers: [{
type: 'logger'
}]
}
}
})
Slack
new NotifmeSdk({
channels: {
slack: {
providers: [{
type: 'webhook',
webhookUrl: 'https://hooks.slack.com/services/Txxxxxxxx/Bxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx'
}]
}
}
})
Custom (define your own)
new NotifmeSdk({
channels: {
slack: {
providers: [{
type: 'custom',
id: 'my-custom-slack-provider...',
send: async (request) => {
// Send slack
return 'id...'
}
}]
}
}
})
request
being of the following type.
See all options: Slack provider options
A multi-provider strategy allows you to customize the send process on a channel.
Strategy name | Description |
---|---|
fallback |
If the used provider returns an error, try the next in the list. |
roundrobin |
Use every provider in turns. If one of them returns an error, fallback to the next. |
no-fallback |
Deactivates fallback strategy. |
You can also provide your own strategy. You have to pass a function implementing:
(Provider[]) => Sender
// See examples below for more details
Examples:
Random strategy
/*
* `providers` is an array containing all the instances that were
* created from your configuration.
*/
const randomStrategy = (providers) => async (request) => {
// Choose one provider at random
const provider = providers[Math.floor(Math.random() * providers.length)];
try {
const id = await provider.send(request)
return {id, providerId: provider.id}
} catch (error) {
error.providerId = provider.id
throw error
}
}
new NotifmeSdk({
channels: {
email: { // Example for email channel
providers: [...],
multiProviderStrategy: randomStrategy
}
}
})
Cheap SMS strategy with fallback
import strategyFallback from 'notifme-sdk/lib/strategies/fallback'
function getCountryFromNumber(number) {
// extract the country from a phone number (+33670707070) -> 'fr'
}
function orderProvidersByPrice(country, providers) {
// giving a country return an array of ordered providers by price
}
const smsCheapStrategy = (providers) => async (request) => {
const country = getCountryFromNumber(request.from)
const providersOrdered = orderProvidersByPrice(country, providers)
return strategyFallback(providersOrdered)(request)
}
If you would like to see another provider or channel, please upvote the corresponding issue (or create one if it does not exist yet).
If you want to have custom channels (and providers) you can add them.
Example:
Custom channel and provider
new NotifmeSdk({
channels: {
socket: {
multiProviderStrategy: 'fallback',
providers: [
{
type: 'custom',
id: 'my-socket-sender',
send: async () => {
return 'custom-socket-id'
}
}
]
}
}
})
New: you can check notifme-template to help you define your templates.
Send an email
notifmeSdk.send({
email: {
from: '[email protected]',
to: '[email protected]',
subject: 'Hi John',
html: '<b>Hello John! How are you?</b>'
}
})
See all parameters.
Send a SMS
notifmeSdk.send({
sms: {
from: '+15000000000',
to: '+15000000001',
text: 'Hello John! How are you?'
}
})
See all parameters.
Call using Voice
notifmeSdk.send({
voice: {
from: '+15000000000',
to: '+15000000001',
url: 'http://demo.twilio.com/docs/voice.xml'
}
})
See all parameters.
Send a push
notifmeSdk.send({
push: {
registrationToken: 'xxxxx',
title: 'Hi John',
body: 'Hello John! How are you?',
icon: 'https://notifme.github.io/notifme-sdk/img/icon.png'
}
})
See all parameters.
Send a webpush
notifmeSdk.send({
webpush: {
subscription: {
keys: {
auth: 'xxxxx',
p256dh: 'xxxxx'
},
endpoint: 'xxxxx'
},
title: 'Hi John',
body: 'Hello John! How are you?',
icon: 'https://notifme.github.io/notifme-sdk/img/icon.png'
}
})
See all parameters.
Send a multi-channel notification
notifmeSdk.send({
email: {
from: '[email protected]',
to: '[email protected]',
subject: 'Hi John',
html: '<b>Hello John! How are you?</b>'
},
sms: {
from: '+15000000000',
to: '+15000000001',
text: 'Hello John! How are you?'
},
push: {
registrationToken: 'xxxxx',
title: 'Hi John',
body: 'Hello John! How are you?',
icon: 'https://notifme.github.io/notifme-sdk/img/icon.png'
},
webpush: {
subscription: {
keys: {
auth: 'xxxxx',
p256dh: 'xxxxx'
},
endpoint: 'xxxxx'
},
title: 'Hi John',
body: 'Hello John! How are you?',
icon: 'https://notifme.github.io/notifme-sdk/img/icon.png'
},
slack: {
text: 'Slack webhook text'
}
})
See all parameters.
send
returns a Promise resolving with an Object
of the following type:
type NotificationStatusType = {
status: 'success' | 'error',
channels?: {[channel: ChannelType]: {
id: string,
providerId: ?string
}},
errors?: {[channel: ChannelType]: Error}
}
Examples:
Case | Returned JSON |
---|---|
Success (when Promise resolves) |
{status: 'success', channels: {sms: {id: 'id-116561976', providerId: 'sms-default-provider'}}} |
Error (here Notification Catcher is not running) |
{status: 'error', channels: {sms: {id: undefined, providerId: 'sms-notificationcatcher-provider'}}, errors: {sms: 'connect ECONNREFUSED 127.0.0.1:1025'}} |
Option name | Usage in production | Comment |
---|---|---|
useNotificationCatcher | false |
Don't forget to deactivate notification catcher (it overrides channels configuration). |
This project uses winston as logging library. You can add or remove loggers as you wish.
import NotifmeSdk from 'notifme-sdk'
import winston from 'winston'
const notifmeSdk = new NotifmeSdk({})
// To deactivate all loggers
notifmeSdk.logger.mute()
// Or set the loggers you want
notifmeSdk.logger.configure([
new (winston.transports.File)({filename: 'somefile.log'})
])
See winston's documentation for more details.
- RabbitMQ: see RabbitMQ Notif.me plugin documentation.
So that we can make a list of people using this library ;)
Contributions are very welcome!
To get started: fork this repository to your own GitHub account and then clone it to your local device.
$ git clone [email protected]:[YOUR_USERNAME]/notifme-sdk.git && cd notifme-sdk
$ yarn install
Before making a pull request, check that the code passes all the unit tests, respects the Standard JS rules, and the Flow type checker.
$ yarn run test
- Implement other providers for each channel (ask or vote for a provider)
- Add other types of notifications based on what people ask (slack, messenger, skype, telegram, kik, spark...)
- A plugin system (for queues, retry system on error, templating, strategies...)
Submit an issue to the project Github if you need any help. And, of course, feel free to submit pull requests with bug fixes or changes.