Rollback to 9d67724e
This commit is contained in:
165
server/_core/emailSender.ts
Normal file
165
server/_core/emailSender.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user