Add a new provider
Steps to add a new provider to Novu
Interested in expanding Novu’s capabilities? By contributing to our growing ecosystem, you can enhance Novu’s reach and impact.
How to add a new provider?
Novu currently supports five channels in_app
, push
, email
, chat
and sms
.
For in_app
we support only our own provider, so new providers cannot be added to this channel. For the other four channels, we support the integration of external providers. This guide will help in adding new providers for any of these 4 channels.
In this guide, we are adding a new provider for the email channel, but all of the mentioned steps are similar for other channels as well.
Description
Providers allow us to handle message delivery over multiple channels.
We have multiple providers for each channel (SMS, Email, Push and Chat). To get started with adding a new provider let’s look at setting up our repository.
Requirements
- Node.js version v20.8.1
- MongoDB
- Redis
- (Optional) pnpm - Needed if you want to install new packages
- (Optional) localstack (required only in S3 related modules)
Need help installing the requirements? Read more here
We have used pnpm package manager in this guide. You can use npm as well.
Initialization
Fork the novu repository and clone it in your local machine.
git clone https://github.com/<'YOUR_GITHUB_USER_NAME'>/novu.git
To set up the repository, run the initial setup command:
pnpm run setup:project
At the root of the project build the node
package to get started.
cd packages/node && pnpm run build
Generate provider
After the project is initialized, a new provider can be generated using the below command.
pnpm run generate:provider
Choose the provider type.
? What type
❯ EMAIL
SMS
PUSH
CHAT
Use up
and down
arrow to switch channel
type and press enter
to select.
For this example, we will be selecting EMAIL
as our provider type. The name for our provider will be example-provider
.
? Write the provider name`kebab-cased` (e.g. proton-mail, outlook365, yahoo-mail): example-provider
Make sure your selected name is not conflicting with our existing provider’s name. Boilerplate files for this new example-provider
is generated in your local machine project.
In above example, we have given our provider name as example-provider for simplicity. If provider you want to add have name as twilio, don’t use twilio-provider as name, instead use twilio only. If one provider supports multiple channels like infobip supports both sms and email channels, use infobip-email or infobip-sms to differentiate these providers.
Once our example-provider
is generated we will need to begin working from within packages/providers/src/lib/example-provider
directory. Make sure to write the test for this new provider.
import {
ChannelTypeEnum,
ISendMessageSuccessResponse,
IEmailOptions,
IEmailProvider,
} from '@novu/stateless';
export class ExampleProviderEmailProvider implements IEmailProvider {
id = 'example-provider'
channelType = ChannelTypeEnum.EMAIL as ChannelTypeEnum.EMAIL;
constructor(
private config: {
apiKey: string;
}
) {}
async sendMessage(options: IEmailOptions): Promise<ISendMessageSuccessResponse> {
return {
id: 'id_returned_by_provider',
date: 'current_time'
}
}
Template test case for example-provider
.
import { ExampleProviderEmailProvider } from "./example-provider.provider";
test("should trigger example-provider library correctly", async () => {});
Add the provider’s SDK as a dependency in the provider’s package.json file. Run
pnpm run setup:project
to build all dependencies again. Use this new sdk method
to complete the provider’s sendMessage
function. Check the reference links
for adding new providers section for each
channel’s provider example.
Add provider logos
In order to present this new provider in the integration store
we need logos in dark and light mode. Add dark color svg logo in apps/web/public/static/images/providers/dark/sqaure
directory and light color svg logo in apps/web/public/static/images/providers/light/sqaure
directory.
Use the provider name as the file name. The sample name for our above-added provider is example-provider.svg
.
Add config items to the list
In order to build the UI integration store, we need to provide it list of all provider integrations. This part is made up of two parts:
- Create credentials config
- Add ProviderId Enum
- Add provider configuration to the providers list
1. Create credentials config
Every provider requires some credentials to create an instance. Novu will add these credentials fields in the integration store provider’s form so that users can use their credentials to connect to their preferred provider to use for that channel notification. For example, in the above added example-provider
, we have only one credential ApiKey
. We will need to add a config object for example-provider
with all existing provider’s configs like below.
export const exampleProviderConfig: IConfigCredentials[] = [
{
key: CredentialsKeyEnum.ApiKey,
displayName: "API Key",
description: "This is API key for example provider",
type: "text",
required: true,
},
...mailConfigBase,
];
- Here the
key
is of typeCredentialsKeyEnum
.
If a new key is added, add this key at these 3 places:-
- In
CredentialsKeyEnum
at filelibs/shared/src/consts/providers/provider.enum.ts
- In
CredentialsDto
at fileapps/api/src/app/integrations/dtos/credentials.dto.ts
- In
credentials
field ofintegrationSchema
at filelibs/dal/src/repositories/integration/integration.schema.ts
displayName
is a human-friendly easy to understand name which will be shown in the provider integration form for this credential.description
is a field that can be used to share more information about the credential.type
here means text field type. this can be a string for text, text for text-area, or a switch for the toggle.required
is of boolean type.mailConfigBase
is an object having default credentials required by anyemail
provider. Make sure not to add duplicate providers which are already there inmailConfigBase
. In the case of another channel provider, we will use that channel config base in place ofmailConfigBase
.
A credential can be made secret by adding in ./secure-credentials.ts file.
2. Add ProviderId Enum
Add this new provider id in the respective channel provider id enum in file libs/shared/src/consts/providers/provider.enum.ts
. As our example-provider
is of email type, add this in EmailProviderIdEnum
with all existing providers like below
export enum EmailProviderIdEnum {
ExampleProvider = "example-provider",
}
3. Add provider to providers list
Now we need to add the provider data to the list located at libs/shared/src/consts/providers/channels/email.ts
. Note that the id
is the provider’s name, displayName
is the provider’s name in Pascal’s case, credentials
are the ones we created in the previous step, logoFileName
should be as it was on the adding logo step (with the format type included).
{
id: 'example-provider',
displayName: 'Example Provider',
channel: ChannelTypeEnum.EMAIL,
credentials: exampleProviderConfig,
// Use valid documentation link
docReference: 'https://docs.example-provider.com/',
logoFileName: { light: 'example-provider.svg', dark: 'example-provider.svg' }
}
Add provider handler in the API
1. Adding the provider dependency in the application-generic service
In the previous step, we created a standalone provider package that will be published to NPM. However currently in our development environment, it is not yet published. In order to use it locally please go to the package.json
located in libs/application-generic/package.json
and add it manually to the dependencies list: "@novu/<NEW_PROVIDER_NAME>": "^<VERSION>"
Please note that the provider name and version can be found from the provider package.json you created earlier.
After adding the dependency run pnpm run setup:project
from the root of the mono repo. so, it can create the required symlinks for the newly created package.
2. Create a provider handler
In order to map internally the different providers’ credentials, we need to add a provider handler at the respective channel handlers located. For Email, it can be found at libs/application-generic/src/factories/mail/handlers
. Other channel handlers can also be found here.
Create a new file example-provider.handler.ts
here with the following code
import { ChannelTypeEnum } from "@novu/shared";
import { ExampleProviderEmailProvider } from "@novu/example-provider";
import { BaseHandler } from "./base.handler";
export class ExampleProviderHandler extends BaseHandler {
constructor() {
super("example-provider", ChannelTypeEnum.EMAIL);
}
buildProvider(credentials, from: string) {
const config: { apiKey: string } = { apiKey: credentials.apiKey };
this.provider = new ExampleProviderEmailProvider(config);
}
}
Add this line given below to export this handler
export * from "./example-provider.handler";
3. Add handler to factory
The last step is to initialize the handler in the factory located in libs/application-generic/src/factories/mail/mail.factory.ts
import { ExampleProviderHandler } from "./handlers";
export class MailFactory {
handlers: IMailHandler[] = [new ExampleProviderHandler()];
}
Final Steps
Now, build the project again using this command
pnpm run setup:project
Run novu in your local machine. Read here to learn on how to run novu on a local machine and test this new provider.
Run the below command in the root of the project to run the providers test
pnpm run test:providers
If everything is working fine without any error, commit your local branch changes, push this branch and create a new pull request to our main repo.
Hurray 🎉! You have successfully added a new provider in Novu!
️ In this guide, we have used only one credential apiKey
for
our example-provider
. This is for reference purposes only. A provider can
have more than one credential as per its SDK
requirements. At each step, you
will need to add all credentials carefully. Check providers referenced below
for more information.
Reference for Adding New Providers
Was this page helpful?