From 63f7fe855f17882d442bb78e3850695688a5e3b1 Mon Sep 17 00:00:00 2001 From: Pawan Jain Date: Tue, 28 Nov 2023 17:56:43 +0530 Subject: [PATCH] fix: senderName and subject override for email providers (#4903) * fix: sendername and subject override for email providers * fix: add sendername in return of compile email * fix: name mistake in sendgrid * fix: add sendername in plunk and netcore * fix: netcore and plunk test --- .../send-message-email.usecase.ts | 21 ++++++++----------- libs/shared/src/types/events/index.ts | 1 + .../mail/handlers/netcore.handler.ts | 7 ++++--- .../factories/mail/handlers/plunk.handler.ts | 3 ++- .../compile-email-template.usecase.ts | 2 +- .../src/lib/provider/provider.interface.ts | 1 + providers/infobip/src/lib/infobip.provider.ts | 2 +- .../src/lib/mailersend.provider.spec.ts | 3 ++- .../mailersend/src/lib/mailersend.provider.ts | 2 +- providers/mailjet/src/lib/mailjet.provider.ts | 2 +- .../mandrill/src/lib/mandrill.provider.ts | 4 ++-- .../netcore/src/lib/netcore.provider.spec.ts | 1 + providers/netcore/src/lib/netcore.provider.ts | 6 +++++- .../nodemailer/src/lib/nodemailer.provider.ts | 2 +- .../outlook365/src/lib/outlook365.provider.ts | 5 ++++- .../plunk/src/lib/plunk.provider.spec.ts | 1 + providers/plunk/src/lib/plunk.provider.ts | 2 ++ .../sendgrid/src/lib/sendgrid.provider.ts | 2 +- .../sendinblue/src/lib/brevo.provider.ts | 4 ++-- providers/ses/src/lib/ses.provider.ts | 6 +++++- 20 files changed, 47 insertions(+), 30 deletions(-) diff --git a/apps/worker/src/app/workflow/usecases/send-message/send-message-email.usecase.ts b/apps/worker/src/app/workflow/usecases/send-message/send-message-email.usecase.ts index ed5d8c0743e..58f1ea7a8b8 100644 --- a/apps/worker/src/app/workflow/usecases/send-message/send-message-email.usecase.ts +++ b/apps/worker/src/app/workflow/usecases/send-message/send-message-email.usecase.ts @@ -158,8 +158,10 @@ export class SendMessageEmail extends SendMessageBase { let html; let subject = step?.template?.subject || ''; let content; + let senderName; const payload = { + senderName: step.template.senderName, subject, preheader: step.template.preheader, content: step.template.content, @@ -203,7 +205,7 @@ export class SendMessageEmail extends SendMessageBase { } try { - ({ html, content, subject } = await this.compileEmailTemplateUsecase.execute( + ({ html, content, subject, senderName } = await this.compileEmailTemplateUsecase.execute( CompileEmailTemplateCommand.create({ environmentId: command.environmentId, organizationId: command.organizationId, @@ -272,6 +274,7 @@ export class SendMessageEmail extends SendMessageBase { html, from: integration?.credentials.from || 'no-reply@novu.co', attachments, + senderName, id: message._id, replyTo: replyToAddress, notificationDetails: { @@ -292,13 +295,7 @@ export class SendMessageEmail extends SendMessageBase { } if (email && integration) { - await this.sendMessage( - integration, - mailData, - message, - command, - overrides?.senderName || step.template.senderName - ); + await this.sendMessage(integration, mailData, message, command); return; } @@ -433,11 +430,10 @@ export class SendMessageEmail extends SendMessageBase { integration: IntegrationEntity, mailData: IEmailOptions, message: MessageEntity, - command: SendMessageCommand, - senderName?: string + command: SendMessageCommand ) { const mailFactory = new MailFactory(); - const mailHandler = mailFactory.getHandler(this.buildFactoryIntegration(integration, senderName), mailData.from); + const mailHandler = mailFactory.getHandler(this.buildFactoryIntegration(integration), mailData.from); try { const result = await mailHandler.send(mailData); @@ -547,7 +543,6 @@ export class SendMessageEmail extends SendMessageBase { ...integration, credentials: { ...integration.credentials, - senderName: senderName && senderName.length > 0 ? senderName : integration.credentials.senderName, }, providerId: integration.providerId, }; @@ -570,6 +565,8 @@ export const createMailData = (options: IEmailOptions, overrides: Record; + senderName?: string; } export interface ITriggerPayload { diff --git a/packages/application-generic/src/factories/mail/handlers/netcore.handler.ts b/packages/application-generic/src/factories/mail/handlers/netcore.handler.ts index a16859ed310..2690777bcd1 100644 --- a/packages/application-generic/src/factories/mail/handlers/netcore.handler.ts +++ b/packages/application-generic/src/factories/mail/handlers/netcore.handler.ts @@ -1,4 +1,4 @@ -import { ChannelTypeEnum } from '@novu/shared'; +import { ChannelTypeEnum, ICredentials } from '@novu/shared'; import { NetCoreProvider } from '@novu/netcore'; import { BaseHandler } from './base.handler'; @@ -7,10 +7,11 @@ export class NetCoreHandler extends BaseHandler { super('netcore', ChannelTypeEnum.EMAIL); } - buildProvider(credentials, from?: string) { - const config: { apiKey: string; from: string } = { + buildProvider(credentials: ICredentials, from?: string) { + const config: { apiKey: string; from: string; senderName: string } = { apiKey: credentials.apiKey, from: from as string, + senderName: credentials.senderName, }; this.provider = new NetCoreProvider(config); diff --git a/packages/application-generic/src/factories/mail/handlers/plunk.handler.ts b/packages/application-generic/src/factories/mail/handlers/plunk.handler.ts index f5c435fdd7a..98e61cfad9c 100644 --- a/packages/application-generic/src/factories/mail/handlers/plunk.handler.ts +++ b/packages/application-generic/src/factories/mail/handlers/plunk.handler.ts @@ -8,8 +8,9 @@ export class PlunkHandler extends BaseHandler { } buildProvider(credentials: ICredentials) { - const config: { apiKey: string } = { + const config: { apiKey: string; senderName: string } = { apiKey: credentials.apiKey, + senderName: credentials.senderName, }; this.provider = new PlunkEmailProvider(config); diff --git a/packages/application-generic/src/usecases/compile-email-template/compile-email-template.usecase.ts b/packages/application-generic/src/usecases/compile-email-template/compile-email-template.usecase.ts index 4e82de3124a..2e556e40058 100644 --- a/packages/application-generic/src/usecases/compile-email-template/compile-email-template.usecase.ts +++ b/packages/application-generic/src/usecases/compile-email-template/compile-email-template.usecase.ts @@ -62,7 +62,7 @@ export class CompileEmailTemplate { } let subject = ''; - let senderName = ''; + let senderName; const content: string | IEmailBlock[] = command.content; let preheader = command.preheader; diff --git a/packages/stateless/src/lib/provider/provider.interface.ts b/packages/stateless/src/lib/provider/provider.interface.ts index 646babf831b..820841d5355 100644 --- a/packages/stateless/src/lib/provider/provider.interface.ts +++ b/packages/stateless/src/lib/provider/provider.interface.ts @@ -24,6 +24,7 @@ export interface IEmailOptions { notificationDetails?: any; ipPoolName?: string; customData?: Record; + senderName?: string; } export interface ISmsOptions { diff --git a/providers/infobip/src/lib/infobip.provider.ts b/providers/infobip/src/lib/infobip.provider.ts index a7324e6fad9..c1ba326a6ee 100644 --- a/providers/infobip/src/lib/infobip.provider.ts +++ b/providers/infobip/src/lib/infobip.provider.ts @@ -110,7 +110,7 @@ export class InfobipEmailProvider implements IEmailProvider { ): Promise { const infobipResponse = await this.infobipClient.channels.email.send({ to: options.to, - from: this.config.from || options.from, + from: options.from || this.config.from, subject: options.subject, text: options.text, html: options.html, diff --git a/providers/mailersend/src/lib/mailersend.provider.spec.ts b/providers/mailersend/src/lib/mailersend.provider.spec.ts index 696235bcc70..09ab6b4c33c 100644 --- a/providers/mailersend/src/lib/mailersend.provider.spec.ts +++ b/providers/mailersend/src/lib/mailersend.provider.spec.ts @@ -4,6 +4,7 @@ import { CheckIntegrationResponseEnum } from '@novu/stateless'; const mockConfig = { apiKey: 'SG.1234', + senderName: 'Novu Team', }; const mockNovuMessage = { @@ -72,7 +73,7 @@ test('should trigger mailerSend correctly', async () => { expect(spy).toBeCalledWith('/email', { method: 'POST', body: { - from: { email: mockNovuMessage.from, name: undefined }, + from: { email: mockNovuMessage.from, name: mockConfig.senderName }, to: [recipient1, recipient2], cc: undefined, bcc: undefined, diff --git a/providers/mailersend/src/lib/mailersend.provider.ts b/providers/mailersend/src/lib/mailersend.provider.ts index 7eb5943c1db..100b97ae074 100644 --- a/providers/mailersend/src/lib/mailersend.provider.ts +++ b/providers/mailersend/src/lib/mailersend.provider.ts @@ -45,7 +45,7 @@ export class MailersendEmailProvider implements IEmailProvider { const emailParams = new EmailParams() .setFrom(options.from ?? this.config.from) - .setFromName(this.config.senderName) + .setFromName(options.senderName || this.config.senderName || '') .setRecipients(recipients) .setSubject(options.subject) .setHtml(options.html) diff --git a/providers/mailjet/src/lib/mailjet.provider.ts b/providers/mailjet/src/lib/mailjet.provider.ts index d692482f617..51e0eb490d0 100644 --- a/providers/mailjet/src/lib/mailjet.provider.ts +++ b/providers/mailjet/src/lib/mailjet.provider.ts @@ -78,7 +78,7 @@ export class MailjetEmailProvider implements IEmailProvider { const message: Mailjet.SendEmailV3_1.Message = { From: { Email: options.from || this.config.from, - Name: this.config.senderName, + Name: options.senderName || this.config.senderName, }, To: options.to.map((email) => ({ Email: email, diff --git a/providers/mandrill/src/lib/mandrill.provider.ts b/providers/mandrill/src/lib/mandrill.provider.ts index 2e1ca9b6caa..e992e3e6dc4 100644 --- a/providers/mandrill/src/lib/mandrill.provider.ts +++ b/providers/mandrill/src/lib/mandrill.provider.ts @@ -46,8 +46,8 @@ export class MandrillProvider implements IEmailProvider { ): Promise { const mandrillSendOption = { message: { - from_email: this.config.from, - from_name: this.config.senderName, + from_email: emailOptions.from || this.config.from, + from_name: emailOptions.senderName || this.config.senderName, subject: emailOptions.subject, html: emailOptions.html, to: this.mapTo(emailOptions), diff --git a/providers/netcore/src/lib/netcore.provider.spec.ts b/providers/netcore/src/lib/netcore.provider.spec.ts index bfb4d852a8a..36d7fcd0c33 100644 --- a/providers/netcore/src/lib/netcore.provider.spec.ts +++ b/providers/netcore/src/lib/netcore.provider.spec.ts @@ -9,6 +9,7 @@ jest.mock('axios'); const mockConfig = { apiKey: 'test-key', from: 'netcore', + senderName: "Novu's Team", }; const mockEmailOptions: IEmailOptions = { diff --git a/providers/netcore/src/lib/netcore.provider.ts b/providers/netcore/src/lib/netcore.provider.ts index 1edd13e50cf..ccccbee54f2 100644 --- a/providers/netcore/src/lib/netcore.provider.ts +++ b/providers/netcore/src/lib/netcore.provider.ts @@ -32,6 +32,7 @@ export class NetCoreProvider implements IEmailProvider { private config: { apiKey: string; from: string; + senderName: string; } ) { this.axiosInstance = axios.create({ @@ -43,7 +44,10 @@ export class NetCoreProvider implements IEmailProvider { options: IEmailOptions ): Promise { const data: IEmailBody = { - from: { email: options.from || this.config.from }, + from: { + email: options.from || this.config.from, + name: options.senderName || this.config.senderName, + }, subject: options.subject, content: [ { diff --git a/providers/nodemailer/src/lib/nodemailer.provider.ts b/providers/nodemailer/src/lib/nodemailer.provider.ts index 0d929257159..fdcb1a21449 100644 --- a/providers/nodemailer/src/lib/nodemailer.provider.ts +++ b/providers/nodemailer/src/lib/nodemailer.provider.ts @@ -126,7 +126,7 @@ export class NodemailerProvider implements IEmailProvider { const sendMailOptions: SendMailOptions = { from: { address: options.from || this.config.from, - name: this.config.senderName || '', + name: options.senderName || this.config.senderName || '', }, to: options.to, subject: options.subject, diff --git a/providers/outlook365/src/lib/outlook365.provider.ts b/providers/outlook365/src/lib/outlook365.provider.ts index 36da19f76c2..6566728aaff 100644 --- a/providers/outlook365/src/lib/outlook365.provider.ts +++ b/providers/outlook365/src/lib/outlook365.provider.ts @@ -70,7 +70,10 @@ export class Outlook365Provider implements IEmailProvider { private createMailData(options: IEmailOptions): SendMailOptions { const sendMailOptions: SendMailOptions = { - from: this.config.from, + from: { + address: options.from || this.config.from, + name: options.senderName || this.config.senderName, + }, to: options.to, subject: options.subject, html: options.html, diff --git a/providers/plunk/src/lib/plunk.provider.spec.ts b/providers/plunk/src/lib/plunk.provider.spec.ts index fbe95e53a79..5ad1f116952 100644 --- a/providers/plunk/src/lib/plunk.provider.spec.ts +++ b/providers/plunk/src/lib/plunk.provider.spec.ts @@ -2,6 +2,7 @@ import { PlunkEmailProvider } from './plunk.provider'; const mockConfig = { apiKey: 'sample-api-key', + senderName: "Novu's Team", }; const mockNovuMessage = { diff --git a/providers/plunk/src/lib/plunk.provider.ts b/providers/plunk/src/lib/plunk.provider.ts index c6caa78bd69..3a360a9071a 100644 --- a/providers/plunk/src/lib/plunk.provider.ts +++ b/providers/plunk/src/lib/plunk.provider.ts @@ -20,6 +20,7 @@ export class PlunkEmailProvider implements IEmailProvider { constructor( private config: { apiKey: string; + senderName: string; } ) { this.plunk = new Plunk(this.config.apiKey); @@ -53,6 +54,7 @@ export class PlunkEmailProvider implements IEmailProvider { ): Promise { const response: IPlunkResponse = await this.plunk.emails.send({ from: options.from, + name: options.senderName || this.config.senderName, to: options.to, subject: options.subject, body: options.html || options.text, diff --git a/providers/sendgrid/src/lib/sendgrid.provider.ts b/providers/sendgrid/src/lib/sendgrid.provider.ts index acaa71ec49d..056885d2acc 100644 --- a/providers/sendgrid/src/lib/sendgrid.provider.ts +++ b/providers/sendgrid/src/lib/sendgrid.provider.ts @@ -77,7 +77,7 @@ export class SendgridEmailProvider implements IEmailProvider { const mailData: Partial = { from: { email: options.from || this.config.from, - name: this.config.senderName, + name: options.senderName || this.config.senderName, }, ...this.getIpPoolObject(options), to: options.to.map((email) => ({ email })), diff --git a/providers/sendinblue/src/lib/brevo.provider.ts b/providers/sendinblue/src/lib/brevo.provider.ts index 666c1df129a..5e1f4e711e4 100644 --- a/providers/sendinblue/src/lib/brevo.provider.ts +++ b/providers/sendinblue/src/lib/brevo.provider.ts @@ -15,7 +15,7 @@ export class BrevoEmailProvider implements IEmailProvider { id = 'sendinblue'; channelType = ChannelTypeEnum.EMAIL as ChannelTypeEnum.EMAIL; private axiosInstance: AxiosInstance; - public readonly BASE_URL = ' https://api.brevo.com/v3'; + public readonly BASE_URL = 'https://api.brevo.com/v3'; constructor( private config: { @@ -35,7 +35,7 @@ export class BrevoEmailProvider implements IEmailProvider { const email: any = {}; email.sender = { email: options.from || this.config.from, - name: this.config.senderName, + name: options.senderName || this.config.senderName, }; email.to = getFormattedTo(options.to); email.subject = options.subject; diff --git a/providers/ses/src/lib/ses.provider.ts b/providers/ses/src/lib/ses.provider.ts index 07e8ba6d0e1..35771a996af 100644 --- a/providers/ses/src/lib/ses.provider.ts +++ b/providers/ses/src/lib/ses.provider.ts @@ -32,6 +32,7 @@ export class SESEmailProvider implements IEmailProvider { text, to, from, + senderName, subject, attachments, cc, @@ -50,7 +51,7 @@ export class SESEmailProvider implements IEmailProvider { attachments, from: { address: from, - name: this.config.senderName, + name: senderName, }, cc, bcc, @@ -68,9 +69,11 @@ export class SESEmailProvider implements IEmailProvider { cc, bcc, replyTo, + senderName, }: IEmailOptions): Promise { const info = await this.sendMail({ from: from || this.config.from, + senderName: senderName || this.config.senderName, to: to, subject: subject, html: html, @@ -162,6 +165,7 @@ export class SESEmailProvider implements IEmailProvider { bcc: [], cc: [], replyTo: 'support@novu.co', + senderName: 'Novu Support', }); return {