/** * 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"; import { sendViaSMTP } from "./smtpSender"; 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 { // 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 { 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 { // 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 if (config.mode === 'production') { // Essayer SMTP en priorité si configuré if (config.provider === 'smtp' && config.smtpHost && config.smtpPort && config.smtpUser && config.smtpPassword) { const sent = await sendViaSMTP(params, { host: config.smtpHost, port: config.smtpPort, secure: config.smtpSecure || 'tls', user: config.smtpUser, password: config.smtpPassword, fromEmail: config.fromEmail, fromName: config.fromName, }); // Si l'envoi échoue, simuler en fallback if (!sent) { return await simulateEmail(params); } return true; } // Sinon essayer Resend if (config.provider === 'resend' && 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; }