207 lines
6.0 KiB
TypeScript
207 lines
6.0 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";
|
|
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<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();
|
|
|
|
console.log('[Email] Configuration récupérée:', config ? {
|
|
provider: config.provider,
|
|
mode: config.mode,
|
|
fromEmail: config.fromEmail,
|
|
hasSmtpHost: !!config.smtpHost,
|
|
hasSmtpUser: !!config.smtpUser,
|
|
hasSmtpPassword: !!config.smtpPassword,
|
|
} : 'Aucune configuration');
|
|
|
|
// Si mode simulation ou pas de config, simuler
|
|
if (!config || config.mode === 'simulation') {
|
|
console.log('[Email] Mode simulation activé ou pas de config');
|
|
return await simulateEmail(params);
|
|
}
|
|
|
|
// Si mode production
|
|
if (config.mode === 'production') {
|
|
console.log('[Email] Mode production activé');
|
|
|
|
// Essayer SMTP en priorité si configuré
|
|
if (config.provider === 'smtp' && config.smtpHost && config.smtpPort && config.smtpUser && config.smtpPassword) {
|
|
console.log('[Email] Tentative d\'envoi via SMTP...');
|
|
|
|
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) {
|
|
console.log('[Email] Échec de l\'envoi SMTP, basculement en simulation');
|
|
return await simulateEmail(params);
|
|
}
|
|
|
|
console.log('[Email] Email envoyé avec succès via SMTP');
|
|
return true;
|
|
}
|
|
|
|
// Sinon essayer Resend
|
|
if (config.provider === 'resend' && config.apiKey) {
|
|
console.log('[Email] Tentative d\'envoi via Resend...');
|
|
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;
|
|
}
|