diff --git a/apps/web/public/static/images/providers/dark/mailtrap.svg b/apps/web/public/static/images/providers/dark/mailtrap.svg new file mode 100644 index 00000000000..4610e880fce --- /dev/null +++ b/apps/web/public/static/images/providers/dark/mailtrap.svg @@ -0,0 +1,26 @@ + diff --git a/apps/web/public/static/images/providers/dark/square/mailtrap.svg b/apps/web/public/static/images/providers/dark/square/mailtrap.svg new file mode 100644 index 00000000000..8662aaf658b --- /dev/null +++ b/apps/web/public/static/images/providers/dark/square/mailtrap.svg @@ -0,0 +1,5 @@ + diff --git a/apps/web/public/static/images/providers/light/mailtrap.svg b/apps/web/public/static/images/providers/light/mailtrap.svg new file mode 100644 index 00000000000..5ad1dd36ee9 --- /dev/null +++ b/apps/web/public/static/images/providers/light/mailtrap.svg @@ -0,0 +1,26 @@ + diff --git a/apps/web/public/static/images/providers/light/square/mailtrap.svg b/apps/web/public/static/images/providers/light/square/mailtrap.svg new file mode 100644 index 00000000000..ca91a016fb1 --- /dev/null +++ b/apps/web/public/static/images/providers/light/square/mailtrap.svg @@ -0,0 +1,5 @@ + diff --git a/libs/shared/src/consts/providers/channels/email.ts b/libs/shared/src/consts/providers/channels/email.ts index e15a681884d..c9aadaa8635 100644 --- a/libs/shared/src/consts/providers/channels/email.ts +++ b/libs/shared/src/consts/providers/channels/email.ts @@ -2,6 +2,7 @@ import { mailerSendConfig, mailgunConfig, mailjetConfig, + mailtrapConfig, mandrillConfig, netCoreConfig, nodemailerConfig, @@ -46,6 +47,14 @@ export const emailProviders: IProviderConfig[] = [ docReference: 'https://docs.novu.co/channels-and-providers/email/mailjet', logoFileName: { light: 'mailjet.png', dark: 'mailjet.png' }, }, + { + id: EmailProviderIdEnum.Mailtrap, + displayName: 'Mailtrap', + channel: ChannelTypeEnum.EMAIL, + credentials: mailtrapConfig, + docReference: 'https://docs.novu.co/channels-and-providers/email/mailtrap', + logoFileName: { light: 'mailtrap.svg', dark: 'mailtrap.svg' }, + }, { id: EmailProviderIdEnum.Mandrill, displayName: 'Mandrill', diff --git a/libs/shared/src/consts/providers/credentials/provider-credentials.ts b/libs/shared/src/consts/providers/credentials/provider-credentials.ts index 7df6a940ace..f48e8c106fe 100644 --- a/libs/shared/src/consts/providers/credentials/provider-credentials.ts +++ b/libs/shared/src/consts/providers/credentials/provider-credentials.ts @@ -220,6 +220,16 @@ export const resendConfig: IConfigCredentials[] = [ ...mailConfigBase, ]; +export const mailtrapConfig: IConfigCredentials[] = [ + { + key: CredentialsKeyEnum.ApiKey, + displayName: 'API Key', + type: 'string', + required: true, + }, + ...mailConfigBase, +]; + export const plunkConfig: IConfigCredentials[] = [ { key: CredentialsKeyEnum.ApiKey, diff --git a/libs/shared/src/consts/providers/provider.enum.ts b/libs/shared/src/consts/providers/provider.enum.ts index 2c763afc11d..9a59244472b 100644 --- a/libs/shared/src/consts/providers/provider.enum.ts +++ b/libs/shared/src/consts/providers/provider.enum.ts @@ -44,6 +44,7 @@ export enum EmailProviderIdEnum { Resend = 'resend', Plunk = 'plunk', MailerSend = 'mailersend', + Mailtrap = 'mailtrap', Clickatell = 'clickatell', Outlook365 = 'outlook365', Novu = 'novu-email', diff --git a/packages/application-generic/package.json b/packages/application-generic/package.json index 8dbb47e4ffd..02463908e22 100644 --- a/packages/application-generic/package.json +++ b/packages/application-generic/package.json @@ -65,6 +65,7 @@ "@novu/mailersend": "^0.20.0-alpha.0", "@novu/mailgun": "^0.20.0-alpha.0", "@novu/mailjet": "^0.20.0-alpha.0", + "@novu/mailtrap": "^0.20.0-alpha.0", "@novu/mandrill": "^0.20.0-alpha.0", "@novu/maqsam": "^0.20.0-alpha.0", "@novu/mattermost": "^0.20.0-alpha.0", diff --git a/packages/application-generic/src/factories/mail/handlers/index.ts b/packages/application-generic/src/factories/mail/handlers/index.ts index 439e1d4913a..78be1d72848 100644 --- a/packages/application-generic/src/factories/mail/handlers/index.ts +++ b/packages/application-generic/src/factories/mail/handlers/index.ts @@ -2,6 +2,7 @@ export * from './sendgrid.handler'; export * from './mailgun.handler'; export * from './emailjs.handler'; export * from './mailjet.handler'; +export * from './mailtrap.handler'; export * from './mandrill.handler'; export * from './nodemailer.handler'; export * from './postmark.handler'; diff --git a/packages/application-generic/src/factories/mail/handlers/mailtrap.handler.ts b/packages/application-generic/src/factories/mail/handlers/mailtrap.handler.ts new file mode 100644 index 00000000000..30fe3eecec2 --- /dev/null +++ b/packages/application-generic/src/factories/mail/handlers/mailtrap.handler.ts @@ -0,0 +1,22 @@ +import { + ChannelTypeEnum, + ICredentials, + EmailProviderIdEnum, +} from '@novu/shared'; +import { MailtrapEmailProvider } from '@novu/mailtrap'; +import { BaseHandler } from './base.handler'; + +export class MailtrapHandler extends BaseHandler { + constructor() { + super(EmailProviderIdEnum.Mailtrap, ChannelTypeEnum.EMAIL); + } + + buildProvider(credentials: ICredentials, from: string) { + const config: { apiKey: string; from: string } = { + from: from as string, + apiKey: credentials.apiKey as string, + }; + + this.provider = new MailtrapEmailProvider(config); + } +} diff --git a/packages/application-generic/src/factories/mail/mail.factory.ts b/packages/application-generic/src/factories/mail/mail.factory.ts index 6d58f4acd2d..374e101f4d9 100644 --- a/packages/application-generic/src/factories/mail/mail.factory.ts +++ b/packages/application-generic/src/factories/mail/mail.factory.ts @@ -4,6 +4,7 @@ import { MailgunHandler, EmailJsHandler, MailjetHandler, + MailtrapHandler, MandrillHandler, NodemailerHandler, PostmarkHandler, @@ -28,6 +29,7 @@ export class MailFactory { new NetCoreHandler(), new EmailJsHandler(), new MailjetHandler(), + new MailtrapHandler(), new MandrillHandler(), new NodemailerHandler(), new PostmarkHandler(), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9b40427fef..bb465b6f62d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1356,6 +1356,7 @@ importers: '@novu/mailersend': ^0.20.0-alpha.0 '@novu/mailgun': ^0.20.0-alpha.0 '@novu/mailjet': ^0.20.0-alpha.0 + '@novu/mailtrap': ^0.20.0-alpha.0 '@novu/mandrill': ^0.20.0-alpha.0 '@novu/maqsam': ^0.20.0-alpha.0 '@novu/mattermost': ^0.20.0-alpha.0 @@ -1448,6 +1449,7 @@ importers: '@novu/mailersend': link:../../providers/mailersend '@novu/mailgun': link:../../providers/mailgun '@novu/mailjet': link:../../providers/mailjet + '@novu/mailtrap': link:../../providers/mailtrap '@novu/mandrill': link:../../providers/mandrill '@novu/maqsam': link:../../providers/maqsam '@novu/mattermost': link:../../providers/mattermost @@ -2609,6 +2611,37 @@ importers: typedoc: 0.24.6_typescript@4.9.5 typescript: 4.9.5 + providers/mailtrap: + specifiers: + '@istanbuljs/nyc-config-typescript': ~1.0.1 + '@novu/stateless': 0.20.0-alpha.0 + '@types/jest': ~27.5.2 + cspell: ~6.19.2 + jest: ~27.5.1 + mailtrap: ^3.1.1 + npm-run-all: ^4.1.5 + nyc: ~15.1.0 + prettier: ~2.8.0 + rimraf: ~3.0.2 + ts-jest: ~27.1.5 + ts-node: ~10.9.1 + typescript: 4.9.5 + dependencies: + '@novu/stateless': link:../../packages/stateless + mailtrap: 3.2.0 + devDependencies: + '@istanbuljs/nyc-config-typescript': 1.0.2_nyc@15.1.0 + '@types/jest': 27.5.2 + cspell: 6.19.2 + jest: 27.5.1_ts-node@10.9.1 + npm-run-all: 4.1.5 + nyc: 15.1.0 + prettier: 2.8.7 + rimraf: 3.0.2 + ts-jest: 27.1.5_tdguimvmawsauzyxxfukpkg77i + ts-node: 10.9.1_wh2cnrlliuuxb2etxm2m3ttgna + typescript: 4.9.5 + providers/mandrill: specifiers: '@istanbuljs/nyc-config-typescript': 1.0.2 @@ -34082,6 +34115,23 @@ packages: uue: 3.1.2 dev: false + /mailtrap/3.2.0: + resolution: {integrity: sha512-G5CwjtVqakHVvTZtPsHp9YTr0PdvmcKTT8leQRIP/ZqhG9nL+F2VifKZggdUSu25uMtCrnEKc3HwWXdzZcjGvQ==} + engines: {node: '>=16.20.1', yarn: '>=1.22.17'} + peerDependencies: + '@types/nodemailer': ^6.4.9 + nodemailer: ^6.9.4 + peerDependenciesMeta: + '@types/nodemailer': + optional: true + nodemailer: + optional: true + dependencies: + axios: 1.4.0 + transitivePeerDependencies: + - debug + dev: false + /make-dir/2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -43906,7 +43956,7 @@ packages: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.4.0 + semver: 7.5.4 typescript: 4.9.5 yargs-parser: 20.2.9 dev: true @@ -43975,7 +44025,7 @@ packages: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.4.0 + semver: 7.5.4 typescript: 4.9.5 yargs-parser: 20.2.9 dev: true @@ -44010,7 +44060,7 @@ packages: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.4.0 + semver: 7.5.4 typescript: 4.9.5 yargs-parser: 20.2.9 dev: true diff --git a/providers/mailtrap/.czrc b/providers/mailtrap/.czrc new file mode 100644 index 00000000000..d1bcc209ca1 --- /dev/null +++ b/providers/mailtrap/.czrc @@ -0,0 +1,3 @@ +{ + "path": "cz-conventional-changelog" +} diff --git a/providers/mailtrap/.eslintrc.json b/providers/mailtrap/.eslintrc.json new file mode 100644 index 00000000000..ec40100be69 --- /dev/null +++ b/providers/mailtrap/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "../../.eslintrc.js" +} diff --git a/providers/mailtrap/.gitignore b/providers/mailtrap/.gitignore new file mode 100644 index 00000000000..963d5292865 --- /dev/null +++ b/providers/mailtrap/.gitignore @@ -0,0 +1,9 @@ +.idea/* +.nyc_output +build +node_modules +test +src/**.js +coverage +*.log +package-lock.json diff --git a/providers/mailtrap/README.md b/providers/mailtrap/README.md new file mode 100644 index 00000000000..9280b3dd9e0 --- /dev/null +++ b/providers/mailtrap/README.md @@ -0,0 +1,13 @@ +# Novu Mailtrap Provider + +A Mailtrap email provider library for [@novu/node](https://github.com/novuhq/novu) + +## Usage + +```javascript +import { MailtrapEmailProvider } from '@novu/mailtrap'; + +const provider = new MailtrapEmailProvider({ + apiKey: process.env.MAILTRAP_API_KEY +}); +``` diff --git a/providers/mailtrap/jest.config.js b/providers/mailtrap/jest.config.js new file mode 100644 index 00000000000..61faa20934a --- /dev/null +++ b/providers/mailtrap/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + axios: 'axios/dist/node/axios.cjs', + }, +}; diff --git a/providers/mailtrap/package.json b/providers/mailtrap/package.json new file mode 100644 index 00000000000..25f6732c0c4 --- /dev/null +++ b/providers/mailtrap/package.json @@ -0,0 +1,82 @@ +{ + "name": "@novu/mailtrap", + "version": "0.20.0-alpha.0", + "description": "A mailtrap wrapper for novu", + "main": "build/main/index.js", + "typings": "build/main/index.d.ts", + "module": "build/module/index.js", + "private": false, + "repository": "https://github.com/novuhq/novu", + "license": "MIT", + "keywords": [], + "scripts": { + "prebuild": "rimraf build", + "build": "run-p build:*", + "build:main": "tsc -p tsconfig.json", + "build:module": "tsc -p tsconfig.module.json", + "fix": "run-s fix:*", + "fix:prettier": "prettier \"src/**/*.ts\" --write", + "fix:lint": "eslint src --ext .ts --fix", + "test": "run-s test:*", + "lint": "eslint src --ext .ts", + "test:unit": "jest src", + "watch:build": "tsc -p tsconfig.json -w", + "watch:test": "jest src --watch", + "reset-hard": "git clean -dfx && git reset --hard && yarn", + "prepare-release": "run-s reset-hard test" + }, + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=13.0.0 <17.0.0", + "pnpm": "^7.26.0" + }, + "dependencies": { + "@novu/stateless": "0.20.0-alpha.0", + "mailtrap": "^3.1.1" + }, + "devDependencies": { + "@istanbuljs/nyc-config-typescript": "~1.0.1", + "@types/jest": "~27.5.2", + "cspell": "~6.19.2", + "jest": "~27.5.1", + "npm-run-all": "^4.1.5", + "nyc": "~15.1.0", + "prettier": "~2.8.0", + "rimraf": "~3.0.2", + "ts-jest": "~27.1.5", + "ts-node": "~10.9.1", + "typescript": "4.9.5" + }, + "files": [ + "build/main", + "build/module", + "!**/*.spec.*", + "!**/*.json", + "CHANGELOG.md", + "LICENSE", + "README.md" + ], + "ava": { + "failFast": true, + "timeout": "60s", + "typescript": { + "rewritePaths": { + "src/": "build/main/" + } + }, + "files": [ + "!build/module/**" + ] + }, + "prettier": { + "singleQuote": true + }, + "nyc": { + "extends": "@istanbuljs/nyc-config-typescript", + "exclude": [ + "**/*.spec.js" + ] + } +} diff --git a/providers/mailtrap/src/index.ts b/providers/mailtrap/src/index.ts new file mode 100644 index 00000000000..8f0fa44883c --- /dev/null +++ b/providers/mailtrap/src/index.ts @@ -0,0 +1 @@ +export * from './lib/mailtrap.provider'; diff --git a/providers/mailtrap/src/lib/mailtrap.provider.spec.ts b/providers/mailtrap/src/lib/mailtrap.provider.spec.ts new file mode 100644 index 00000000000..c7386f2fdb1 --- /dev/null +++ b/providers/mailtrap/src/lib/mailtrap.provider.spec.ts @@ -0,0 +1,64 @@ +import { MailtrapEmailProvider } from './mailtrap.provider'; +import { MailtrapClient, SendResponse } from 'mailtrap'; +import { CheckIntegrationResponseEnum } from '@novu/stateless'; + +const mockConfig = { + apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + from: 'test@test.com', +}; + +const mockNovuMessage = { + from: 'test@test.com', + to: ['test@test.com'], + html: '