From 06270ff74715461571a82eec9aa786cf473f603d Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:07:10 +0100 Subject: [PATCH] - fixes - allow mail from address override - queue cloud emails --- .../workspace/services/workspace.service.ts | 25 +++++++--- apps/server/src/ee | 2 +- .../src/integrations/mail/mail.service.ts | 15 ++++-- .../queue/constants/queue.constants.ts | 3 +- .../emails/cloud/trial-ended-email.tsx | 46 ------------------- package.json | 2 +- 6 files changed, 35 insertions(+), 58 deletions(-) delete mode 100644 apps/server/src/integrations/transactional/emails/cloud/trial-ended-email.tsx diff --git a/apps/server/src/core/workspace/services/workspace.service.ts b/apps/server/src/core/workspace/services/workspace.service.ts index 3ddcc5a0..4c6c8d09 100644 --- a/apps/server/src/core/workspace/services/workspace.service.ts +++ b/apps/server/src/core/workspace/services/workspace.service.ts @@ -2,6 +2,7 @@ import { BadRequestException, ForbiddenException, Injectable, + Logger, NotFoundException, } from '@nestjs/common'; import { CreateWorkspaceDto } from '../dto/create-workspace.dto'; @@ -32,6 +33,8 @@ import { Queue } from 'bullmq'; @Injectable() export class WorkspaceService { + private readonly logger = new Logger(WorkspaceService.name); + constructor( private workspaceRepo: WorkspaceRepo, private spaceService: SpaceService, @@ -205,13 +208,23 @@ export class WorkspaceService { ); if (this.environmentService.isCloud() && trialEndAt) { - const delay = trialEndAt.getTime() - Date.now(); + try { + const delay = trialEndAt.getTime() - Date.now(); - await this.billingQueue.add( - QueueJob.TRIAL_ENDED, - { workspaceId: createdWorkspace.id }, - { delay }, - ); + await this.billingQueue.add( + QueueJob.TRIAL_ENDED, + { workspaceId: createdWorkspace.id }, + { delay }, + ); + + await this.billingQueue.add( + QueueJob.WELCOME_EMAIL, + { userId: user.id }, + { delay: 60 * 1000 }, // 1m + ); + } catch (err) { + this.logger.error(err); + } } return createdWorkspace; diff --git a/apps/server/src/ee b/apps/server/src/ee index 2d9bc2b3..a04fcc22 160000 --- a/apps/server/src/ee +++ b/apps/server/src/ee @@ -1 +1 @@ -Subproject commit 2d9bc2b3946ea0e1cbc76ccf7ea71a3e61e93353 +Subproject commit a04fcc224e36514741f064d83a3c39df31766b65 diff --git a/apps/server/src/integrations/mail/mail.service.ts b/apps/server/src/integrations/mail/mail.service.ts index 46625cc3..035b2706 100644 --- a/apps/server/src/integrations/mail/mail.service.ts +++ b/apps/server/src/integrations/mail/mail.service.ts @@ -19,18 +19,27 @@ export class MailService { async sendEmail(message: MailMessage): Promise { if (message.template) { // in case this method is used directly. we do not send the tsx template from queue - message.html = await render(message.template, { pretty: true }); + message.html = await render(message.template, { + pretty: true, + }); message.text = await render(message.template, { plainText: true }); } - const sender = `${this.environmentService.getMailFromName()} <${this.environmentService.getMailFromAddress()}> `; + let from = this.environmentService.getMailFromAddress(); + if (message.from) { + from = message.from; + } + + const sender = `${this.environmentService.getMailFromName()} <${from}> `; await this.mailDriver.sendMail({ from: sender, ...message }); } async sendToQueue(message: MailMessage): Promise { if (message.template) { // transform the React object because it gets lost when sent via the queue - message.html = await render(message.template, { pretty: true }); + message.html = await render(message.template, { + pretty: true, + }); message.text = await render(message.template, { plainText: true, }); diff --git a/apps/server/src/integrations/queue/constants/queue.constants.ts b/apps/server/src/integrations/queue/constants/queue.constants.ts index 3941b11d..d1678ea3 100644 --- a/apps/server/src/integrations/queue/constants/queue.constants.ts +++ b/apps/server/src/integrations/queue/constants/queue.constants.ts @@ -14,6 +14,7 @@ export enum QueueJob { PAGE_BACKLINKS = 'page-backlinks', STRIPE_SEATS_SYNC = 'sync-stripe-seats', - TRIAL_ENDED = 'trial-ended', + WELCOME_EMAIL = 'welcome-email', + FIRST_PAYMENT_EMAIL = 'first-payment-email', } diff --git a/apps/server/src/integrations/transactional/emails/cloud/trial-ended-email.tsx b/apps/server/src/integrations/transactional/emails/cloud/trial-ended-email.tsx deleted file mode 100644 index f07a54dc..00000000 --- a/apps/server/src/integrations/transactional/emails/cloud/trial-ended-email.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Section, Text, Button } from '@react-email/components'; -import * as React from 'react'; -import { button, content, paragraph } from '@docmost/transactional/css/styles'; -import { MailBody } from '@docmost/transactional/partials/partials'; - -interface Props { - billingLink: string; - workspaceName: string; -} - -export const TrialEndedEmail = ({ billingLink, workspaceName }: Props) => { - return ( - -
- Hi there, - - Your Docmost 7-day free trial for {workspaceName} has come to an end. - - - To continue using Docmost for your wiki and documentation, please - upgrade to a premium plan. - -
-
- -
-
- - PS: If you would like to extend your trial, please reply this email. - -
-
- ); -}; - -export default TrialEndedEmail; diff --git a/package.json b/package.json index ae181dbe..64cf9267 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "client:dev": "nx run client:dev", "server:dev": "nx run server:start:dev", "server:start": "nx run server:start:prod", - "email:dev": "nx run @docmost/transactional:dev", + "email:dev": "nx run server:email:dev", "dev": "pnpm concurrently -n \"frontend,backend\" -c \"cyan,green\" \"pnpm run client:dev\" \"pnpm run server:dev\"" }, "dependencies": {