diff --git a/mail/html/reset-password.hbs b/mail/html/reset-password.hbs new file mode 100644 index 0000000..e69de29 diff --git a/mail/text/reset-password.hbs b/mail/text/reset-password.hbs new file mode 100644 index 0000000..e69de29 diff --git a/src/config/config.ts b/src/config/config.ts index 9441a7b..2114cdc 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -2,6 +2,7 @@ export default async () => ({ base: { localUrl: `${process.env.BASE_URL}`, fromEmail: `${process.env.FROM_EMAIL}`, + appName: `${process.env.APP_NAME ?? 'Waterwolf Auth'}`, }, redis: { host: process.env['REDIS_HOST'] ?? 'localhost', diff --git a/src/mail/mail.service.ts b/src/mail/mail.service.ts index 39327ba..e9cdf88 100644 --- a/src/mail/mail.service.ts +++ b/src/mail/mail.service.ts @@ -18,29 +18,60 @@ export class MailService { * Send a password reset email to the user * @param email The email address of the user */ - public async sendPasswordResetEmail(email: string, resetCode: string): Promise {} + public async sendPasswordResetEmail(email: string, resetCode: string): Promise { + this.logger.debug(`Sending password reset email to ${email}`); + + const resetUrl = `${this.configService.getOrThrow('base.localUrl')}/auth/reset-password?code=${resetCode}`; + + const { html: templateHtml, text: templateText } = await this.fetchTemplate('reset-password'); + + const html = Handlebars.compile(templateHtml)({ resetUrl }); + const text = Handlebars.compile(templateText)({ resetUrl }); + + this.postalService.sendMessage({ + to: [email], + subject: 'Reset your password', + from: this.configService.getOrThrow('MAIL_FROM'), + plain_body: text, + html_body: html, + }); + } /** * Send a welcome email to the user * @param email The email address of the user */ - public async sendWelcomeEmail(email: string): Promise {} + public async sendWelcomeEmail(email: string): Promise { + this.logger.debug(`Sending verification email to ${email}`); + + const { html: templateHtml, text: templateText } = await this.fetchTemplate('welcome'); + + const html = Handlebars.compile(templateHtml)({}); + const text = Handlebars.compile(templateText)({}); + + this.postalService.sendMessage({ + to: [email], + subject: `Welcome to ${this.configService.getOrThrow('base.appName')}`, + from: this.configService.getOrThrow('MAIL_FROM'), + plain_body: text, + html_body: html, + }); + } /** * Send a verification email to the user * @param email The email address of the user */ public async sendVerificationEmail(email: string, code: string): Promise { - this.logger.debug(`Sending welcome email to ${email}`); + this.logger.debug(`Sending verification email to ${email}`); - const verificationUrl = `${this.configService.getOrThrow('BASE_URL')}/auth/verify?code=${code}`; + const verificationUrl = `${this.configService.getOrThrow('base.localUrl')}/auth/verify?code=${code}`; //handlebar render email template const { html: templateHtml, text: templateText } = await this.fetchTemplate('verify-email'); //replace the placeholders with the actual values - const template = Handlebars.compile(templateHtml); - const html = template({ verificationUrl }); + const html = Handlebars.compile(templateHtml)({ verificationUrl }); const text = Handlebars.compile(templateText)({ verificationUrl }); this.postalService.sendMessage({ @@ -56,7 +87,22 @@ export class MailService { * Send a password changed email to the user * @param email The email address of the user */ - public async sendPasswordChangedEmail(email: string): Promise {} + public async sendPasswordChangedEmail(email: string): Promise { + this.logger.debug(`Sending password changed email to ${email}`); + + const { html: templateHtml, text: templateText } = await this.fetchTemplate('password-changed'); + + const html = Handlebars.compile(templateHtml)({}); + const text = Handlebars.compile(templateText)({}); + + this.postalService.sendMessage({ + to: [email], + subject: 'Password changed', + from: this.configService.getOrThrow('MAIL_FROM'), + plain_body: text, + html_body: html, + }); + } /** * Private function. Reads the html email template from the file system and returns the content