Files
formation-manager-itinova/server/_core/emailSender.ts
2025-11-19 08:41:10 -05:00

166 lines
4.6 KiB
TypeScript

/**
* Service d'envoi d'emails réels via Resend API
*
* Configuration requise:
* - RESEND_API_KEY: Clé API Resend (obtenir sur https://resend.com)
* - RESEND_FROM_EMAIL: Adresse email d'envoi (doit être vérifiée dans Resend)
*
* Si ces variables ne sont pas configurées, les emails seront simulés
* et envoyés comme notifications au propriétaire du projet.
*/
import { ENV } from "./env";
import { notifyOwner } from "./notification";
import { getActiveEmailConfig } from "../db";
interface EmailParams {
to: string;
subject: string;
html: string;
attachments?: Array<{
filename: string;
content: string;
contentType: string;
}>;
}
interface ResendEmailRequest {
from: string;
to: string[];
subject: string;
html: string;
attachments?: Array<{
filename: string;
content: string;
}>;
}
/**
* Envoie un email via Resend API
*/
async function sendViaResend(params: EmailParams, config?: { apiKey: string; fromEmail: string; fromName: string }): Promise<boolean> {
// Utiliser la config fournie ou les variables d'environnement
const resendApiKey = config?.apiKey || process.env.RESEND_API_KEY;
const fromEmail = config?.fromEmail || process.env.RESEND_FROM_EMAIL || 'noreply@manusvm.computer';
const fromName = config?.fromName || 'Formation Manager Itinova';
if (!resendApiKey) {
console.warn('[Email] RESEND_API_KEY non configurée, email simulé');
return false;
}
try {
const payload: ResendEmailRequest = {
from: `${fromName} <${fromEmail}>`,
to: [params.to],
subject: params.subject,
html: params.html,
};
// Ajouter les pièces jointes si présentes
if (params.attachments && params.attachments.length > 0) {
payload.attachments = params.attachments.map(att => ({
filename: att.filename,
content: att.content, // Resend accepte base64 ou string
}));
}
const response = await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${resendApiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const error = await response.text();
console.error('[Email] Erreur Resend:', response.status, error);
return false;
}
const result = await response.json();
console.log('[Email] Email envoyé via Resend:', result.id);
return true;
} catch (error) {
console.error('[Email] Exception lors de l\'envoi via Resend:', error);
return false;
}
}
/**
* Simule l'envoi d'un email en créant une notification pour le propriétaire
*/
async function simulateEmail(params: EmailParams): Promise<boolean> {
console.log('=== EMAIL SIMULÉ ===');
console.log('To:', params.to);
console.log('Subject:', params.subject);
const emailContent = `
Destinataire: ${params.to}
Sujet: ${params.subject}
${params.html.replace(/<[^>]*>/g, '').substring(0, 500)}...
${params.attachments ? `Pièces jointes: ${params.attachments.map(a => a.filename).join(', ')}` : ''}
⚠️ Cet email est simulé. Pour envoyer de vrais emails:
1. Créez un compte sur https://resend.com
2. Ajoutez RESEND_API_KEY dans les secrets du projet
3. Ajoutez RESEND_FROM_EMAIL (ex: noreply@votredomaine.com)`;
try {
await notifyOwner({
title: `📧 Email simulé: ${params.subject}`,
content: emailContent,
});
console.log('✓ Email simulé (notification envoyée au propriétaire)');
} catch (error) {
console.error('Erreur lors de la simulation d\'email:', error);
}
console.log('===================');
return true;
}
/**
* Envoie un email (réel ou simulé selon la configuration)
*/
export async function sendEmail(params: EmailParams): Promise<boolean> {
// Récupérer la configuration depuis la base de données
const config = await getActiveEmailConfig();
// Si mode simulation ou pas de config, simuler
if (!config || config.mode === 'simulation') {
return await simulateEmail(params);
}
// Si mode production, tenter d'envoyer via Resend
if (config.mode === 'production' && config.apiKey) {
const sent = await sendViaResend(params, {
apiKey: config.apiKey,
fromEmail: config.fromEmail,
fromName: config.fromName,
});
// Si l'envoi échoue, simuler en fallback
if (!sent) {
return await simulateEmail(params);
}
return true;
}
// Fallback: simuler
return await simulateEmail(params);
}
/**
* Vérifie si le service d'envoi d'emails réel est configuré
*/
export function isEmailServiceConfigured(): boolean {
return !!process.env.RESEND_API_KEY;
}