import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { MailerService } from '@nestjs-modules/mailer'; @Injectable() export class MailService { private readonly logger = new Logger(MailService.name); private readonly appUrl: string; constructor( private mailerService: MailerService, private configService: ConfigService, ) { this.appUrl = this.configService.get( 'TESSERA_APP_URL', 'http://localhost:3000', ); } /** * Send a password reset email with a time-limited token link. * T-02-12: The caller always returns 200 regardless of whether this succeeds * (no email enumeration). */ async sendPasswordResetEmail( email: string, token: string, locale: string = 'de', ): Promise { const resetLink = `${this.appUrl}/reset-password/${token}`; const isGerman = locale === 'de'; const subject = isGerman ? 'Passwort zurücksetzen - Tessera' : 'Reset your password - Tessera'; const text = isGerman ? [ 'Hallo,', '', 'Sie haben eine Passwortzurücksetzung für Ihren Tessera-Account angefordert.', '', `Klicken Sie auf den folgenden Link, um Ihr Passwort zurückzusetzen:`, resetLink, '', 'Dieser Link ist 1 Stunde gültig und kann nur einmal verwendet werden.', '', 'Falls Sie diese Anfrage nicht gestellt haben, können Sie diese E-Mail ignorieren.', '', 'Mit freundlichen Grüßen,', 'Ihr Tessera-Team', ].join('\n') : [ 'Hello,', '', 'You have requested a password reset for your Tessera account.', '', 'Click the following link to reset your password:', resetLink, '', 'This link is valid for 1 hour and can only be used once.', '', 'If you did not request this, you can safely ignore this email.', '', 'Best regards,', 'The Tessera Team', ].join('\n'); try { await this.mailerService.sendMail({ to: email, subject, text, }); this.logger.log(`Password reset email sent to ${email}`); } catch (error) { // Log but don't throw -- caller returns 200 regardless (T-02-12) this.logger.error( `Failed to send password reset email to ${email}`, error instanceof Error ? error.stack : String(error), ); } } /** * Send a welcome email to a newly created user (optional). */ async sendWelcomeEmail( email: string, username: string, locale: string = 'de', ): Promise { const isGerman = locale === 'de'; const subject = isGerman ? 'Willkommen bei Tessera' : 'Welcome to Tessera'; const text = isGerman ? [ `Hallo ${username},`, '', 'Ihr Tessera-Account wurde erstellt.', '', `Sie können sich unter ${this.appUrl}/login anmelden.`, '', 'Mit freundlichen Grüßen,', 'Ihr Tessera-Team', ].join('\n') : [ `Hello ${username},`, '', 'Your Tessera account has been created.', '', `You can sign in at ${this.appUrl}/login.`, '', 'Best regards,', 'The Tessera Team', ].join('\n'); try { await this.mailerService.sendMail({ to: email, subject, text, }); this.logger.log(`Welcome email sent to ${email}`); } catch (error) { this.logger.error( `Failed to send welcome email to ${email}`, error instanceof Error ? error.stack : String(error), ); } } }