CognxSafeTrack
feat: migrate to multi-tenant SaaS architecture with JWT auth and BullMQ notifications
2ab1980 | import axios from 'axios'; | |
| import { logger } from '../logger'; | |
| const BREVO_API_KEY = process.env.BREVO_API_KEY; | |
| const BREVO_API_URL = 'https://api.brevo.com/v3/smtp/email'; | |
| export class EmailService { | |
| static async sendWelcomeEmail(to: string, name: string, organizationName: string, loginUrl: string, passwordResetUrl: string) { | |
| if (!BREVO_API_KEY) { | |
| logger.warn('[EMAIL] BREVO_API_KEY not found. Skipping email sending.'); | |
| return; | |
| } | |
| try { | |
| const response = await axios.post( | |
| BREVO_API_URL, | |
| { | |
| sender: { name: 'Xamlé Studio', email: 'contact@xamle.studio' }, | |
| to: [{ email: to, name }], | |
| subject: `Bienvenue chez Xamlé Studio - ${organizationName}`, | |
| htmlContent: ` | |
| <div style="font-family: sans-serif; max-width: 600px; margin: auto; padding: 20px; border: 1px solid #eee; border-radius: 10px;"> | |
| <h2 style="color: #1e293b;">Bienvenue, ${name} !</h2> | |
| <p>Votre espace pour <strong>${organizationName}</strong> a été créé avec succès.</p> | |
| <p>Vous pouvez vous connecter à votre tableau de bord en cliquant sur le bouton ci-dessous :</p> | |
| <a href="${loginUrl}" style="display: inline-block; padding: 12px 24px; background-color: #059669; color: white; text-decoration: none; border-radius: 8px; font-weight: bold; margin: 20px 0;">Accéder au Dashboard</a> | |
| <p>Pour des raisons de sécurité, nous vous recommandons de configurer votre mot de passe immédiatement via ce lien :</p> | |
| <a href="${passwordResetUrl}">${passwordResetUrl}</a> | |
| <p style="color: #64748b; font-size: 0.875rem; margin-top: 40px;">L'équipe Xamlé Studio</p> | |
| </div> | |
| ` | |
| }, | |
| { | |
| headers: { | |
| 'api-key': BREVO_API_KEY, | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| logger.info(`[EMAIL] Welcome email sent to ${to} (Brevo ID: ${response.data.messageId})`); | |
| } catch (error: any) { | |
| logger.error(`[EMAIL] Failed to send welcome email to ${to}: ${error.response?.data?.message || error.message}`); | |
| } | |
| } | |
| static async sendInvitationEmail(to: string, invitedBy: string, organizationName: string, joinUrl: string) { | |
| if (!BREVO_API_KEY) { | |
| logger.warn('[EMAIL] BREVO_API_KEY not found. Skipping email sending.'); | |
| return; | |
| } | |
| try { | |
| await axios.post( | |
| BREVO_API_URL, | |
| { | |
| sender: { name: 'Xamlé Studio', email: 'contact@xamle.studio' }, | |
| to: [{ email: to }], | |
| subject: `${invitedBy} vous invite à rejoindre ${organizationName}`, | |
| htmlContent: ` | |
| <div style="font-family: sans-serif; max-width: 600px; margin: auto; padding: 20px; border: 1px solid #eee; border-radius: 10px;"> | |
| <h2 style="color: #1e293b;">Rejoignez votre équipe !</h2> | |
| <p><strong>${invitedBy}</strong> vous a invité à collaborer sur l'espace <strong>${organizationName}</strong>.</p> | |
| <p>Cliquez ci-dessous pour activer votre compte :</p> | |
| <a href="${joinUrl}" style="display: inline-block; padding: 12px 24px; background-color: #059669; color: white; text-decoration: none; border-radius: 8px; font-weight: bold; margin: 20px 0;">Rejoindre l'équipe</a> | |
| <p style="color: #64748b; font-size: 0.875rem; margin-top: 40px;">L'équipe Xamlé Studio</p> | |
| </div> | |
| ` | |
| }, | |
| { | |
| headers: { | |
| 'api-key': BREVO_API_KEY, | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| logger.info(`[EMAIL] Invitation sent to ${to}`); | |
| } catch (error: any) { | |
| logger.error(`[EMAIL] Failed to send invitation to ${to}: ${error.response?.data?.message || error.message}`); | |
| } | |
| } | |
| } | |