Spaces:
Runtime error
Runtime error
| import { Injectable, Logger } from '@nestjs/common'; | |
| import { ConfigService } from '@nestjs/config'; | |
| import { EmailConfig } from './email.config'; | |
| () | |
| export class EmailService { | |
| private readonly logger = new Logger(EmailService.name); | |
| private readonly config: EmailConfig; | |
| constructor(configService: ConfigService) { | |
| this.config = new EmailConfig(configService); | |
| } | |
| async sendOtpEmail( | |
| email: string, | |
| otp: string, | |
| firstName?: string, | |
| ): Promise<void> { | |
| try { | |
| this.logger.log(`π§ Attempting to send OTP email to: ${email}`); | |
| const greeting = firstName ? `Hi ${firstName}` : 'Hello'; | |
| const payload = { | |
| sender: { | |
| email: this.config.otpEmail, | |
| name: 'StreamFlix', | |
| }, | |
| to: [{ email, name: firstName || email }], | |
| templateId: this.config.otpTemplateId, | |
| params: { | |
| GREETING: greeting, | |
| OTP: otp, | |
| }, | |
| }; | |
| this.logger.log('π§ OTP Email payload:', { | |
| sender: payload.sender, | |
| to: payload.to, | |
| templateId: payload.templateId, | |
| params: payload.params, | |
| }); | |
| const response = await fetch('https://api.brevo.com/v3/smtp/email', { | |
| method: 'POST', | |
| headers: { | |
| 'api-key': this.config.apiKey, | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(payload), | |
| }); | |
| const responseText = await response.text(); | |
| this.logger.log(`π§ Raw Response: ${responseText}`); | |
| if (!response.ok) { | |
| let error; | |
| try { | |
| error = JSON.parse(responseText); | |
| } catch { | |
| error = responseText; | |
| } | |
| this.logger.error('π§ Failed to send OTP email:', error); | |
| throw new Error('Failed to send OTP email'); | |
| } | |
| this.logger.log(`π§ β OTP email sent successfully to ${email}`); | |
| } catch (error) { | |
| this.logger.error('π§ β Error sending OTP email:', error); | |
| throw error; | |
| } | |
| } | |
| async sendWelcomeEmail( | |
| email: string, | |
| firstName: string, | |
| lastName: string, | |
| ): Promise<void> { | |
| try { | |
| this.logger.log(`π§ Attempting to send welcome email to: ${email}`); | |
| const fullName = `${firstName} ${lastName}`.trim(); | |
| const payload = { | |
| sender: { | |
| email: this.config.welcomeEmail, | |
| name: 'StreamFlix', | |
| }, | |
| to: [{ email, name: fullName || email }], | |
| templateId: this.config.welcomeTemplateId, | |
| params: { | |
| FIRSTNAME: fullName || firstName || 'User', | |
| }, | |
| }; | |
| this.logger.log('π§ Welcome Email payload:', { | |
| sender: payload.sender, | |
| to: payload.to, | |
| templateId: payload.templateId, | |
| params: payload.params, | |
| }); | |
| const response = await fetch('https://api.brevo.com/v3/smtp/email', { | |
| method: 'POST', | |
| headers: { | |
| 'api-key': this.config.apiKey, | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(payload), | |
| }); | |
| const responseText = await response.text(); | |
| this.logger.log(`π§ Raw Response: ${responseText}`); | |
| if (!response.ok) { | |
| let error; | |
| try { | |
| error = JSON.parse(responseText); | |
| } catch { | |
| error = responseText; | |
| } | |
| this.logger.error('π§ Failed to send welcome email:', error); | |
| throw new Error('Failed to send welcome email'); | |
| } | |
| this.logger.log(`π§ β Welcome email sent successfully to ${email}`); | |
| } catch (error) { | |
| this.logger.error('π§ β Error sending welcome email:', error); | |
| throw error; | |
| } | |
| } | |
| async send2FACode( | |
| email: string, | |
| name: string, | |
| code: string, | |
| ipAddress?: string, | |
| userAgent?: string, | |
| location?: string, | |
| ): Promise<void> { | |
| try { | |
| this.logger.log(`π§ Attempting to send 2FA code to: ${email}`); | |
| const payload = { | |
| sender: { | |
| email: this.config.otpEmail, | |
| name: 'StreamFlix Security', | |
| }, | |
| to: [{ email, name: name || email }], | |
| templateId: parseInt(process.env.BREVO_2FA_CODE_TEMPLATE_ID || '4', 10), | |
| params: { | |
| adminName: name, | |
| verificationCode: code, | |
| expiryMinutes: process.env.TWO_FA_CODE_EXPIRY_MINUTES || '10', | |
| location: location || 'Unknown Location', | |
| ipAddress: ipAddress || 'Unknown', | |
| deviceInfo: userAgent || 'Unknown device', | |
| timestamp: new Date().toLocaleString('en-US', { | |
| dateStyle: 'long', | |
| timeStyle: 'short', | |
| }), | |
| supportUrl: process.env.SUPPORT_URL || '#', | |
| securityUrl: process.env.SECURITY_URL || '#', | |
| privacyUrl: process.env.PRIVACY_URL || '#', | |
| currentYear: new Date().getFullYear().toString(), | |
| companyAddress: process.env.COMPANY_ADDRESS || '', | |
| }, | |
| }; | |
| this.logger.log('π§ 2FA Code Email payload:', { | |
| sender: payload.sender, | |
| to: payload.to, | |
| templateId: payload.templateId, | |
| params: { ...payload.params, verificationCode: '******' }, // Hide code in logs | |
| }); | |
| const response = await fetch('https://api.brevo.com/v3/smtp/email', { | |
| method: 'POST', | |
| headers: { | |
| 'api-key': this.config.apiKey, | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(payload), | |
| }); | |
| const responseText = await response.text(); | |
| this.logger.log(`π§ Raw Response: ${responseText}`); | |
| if (!response.ok) { | |
| let error; | |
| try { | |
| error = JSON.parse(responseText); | |
| } catch { | |
| error = responseText; | |
| } | |
| this.logger.error('π§ Failed to send 2FA code email:', error); | |
| throw new Error('Failed to send 2FA code email'); | |
| } | |
| this.logger.log(`π§ β 2FA code sent successfully to ${email}`); | |
| } catch (error) { | |
| this.logger.error('π§ β Error sending 2FA code:', error); | |
| throw error; | |
| } | |
| } | |
| } | |