edtech / apps /api /src /services /email.ts
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}`);
}
}
}