## Problèmes résolus ### Bug 1 : Seulement 2 invitations sur 3 envoyées **Cause :** Tentative de conversion base64 incorrecte qui corrompait la première invitation **Solution :** Conversion explicite Buffer → base64 avec encodage UTF-8 pour toutes les invitations ### Bug 2 : Fichiers ICS corrompus (erreur Outlook "Nous n'avons pas pu importer le calendrier") **Cause :** Encodage incorrect lors de la transmission SMTP **Solution :** Conversion UTF-8 → base64 explicite avec contentType correct ## Modifications techniques - `server/emailService.ts` : Conversion explicite en base64 UTF-8 pour chaque invitation ICS - `server/_core/smtpSender.ts` : Ajout de logs détaillés pour tracer les pièces jointes - ContentType : `text/calendar; charset=utf-8` (sans method=REQUEST qui posait problème) ## Déploiement ✅ Serveur TEST (108.143.67.56) - Validé ✅ Serveur PROD (98.71.216.234) - Déployé Les apprenants reçoivent maintenant les 3 invitations ICS et peuvent les importer correctement dans Outlook.
117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
/**
|
|
* Service d'envoi d'emails via SMTP avec nodemailer
|
|
*/
|
|
|
|
import nodemailer from 'nodemailer';
|
|
import type { Transporter } from 'nodemailer';
|
|
|
|
interface EmailParams {
|
|
to: string;
|
|
subject: string;
|
|
html: string;
|
|
attachments?: Array<{
|
|
filename: string;
|
|
content: string;
|
|
contentType: string;
|
|
}>;
|
|
}
|
|
|
|
interface SMTPConfig {
|
|
host: string;
|
|
port: number;
|
|
secure: 'none' | 'tls' | 'ssl';
|
|
user: string;
|
|
password: string;
|
|
fromEmail: string;
|
|
fromName: string;
|
|
}
|
|
|
|
/**
|
|
* Crée un transporteur nodemailer à partir de la configuration SMTP
|
|
*/
|
|
function createTransporter(config: SMTPConfig): Transporter {
|
|
const secure = config.secure === 'ssl'; // true pour SSL (port 465), false pour TLS/STARTTLS
|
|
|
|
return nodemailer.createTransport({
|
|
host: config.host,
|
|
port: config.port,
|
|
secure: secure,
|
|
auth: {
|
|
user: config.user,
|
|
pass: config.password,
|
|
},
|
|
// Options supplémentaires pour améliorer la compatibilité
|
|
tls: {
|
|
// Ne pas échouer sur les certificats invalides (à utiliser avec précaution en production)
|
|
rejectUnauthorized: false,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Envoie un email via SMTP
|
|
*/
|
|
export async function sendViaSMTP(params: EmailParams, config: SMTPConfig): Promise<boolean> {
|
|
try {
|
|
const transporter = createTransporter(config);
|
|
|
|
// Préparer les pièces jointes
|
|
console.log(`[SMTP] Nombre de pièces jointes reçues: ${params.attachments?.length || 0}`);
|
|
if (params.attachments) {
|
|
params.attachments.forEach((att, idx) => {
|
|
console.log(`[SMTP] Attachment ${idx + 1}: ${att.filename}, contentType: ${att.contentType}, size: ${att.content.length} chars`);
|
|
});
|
|
}
|
|
|
|
const attachments = params.attachments?.map(att => ({
|
|
filename: att.filename,
|
|
content: att.content,
|
|
encoding: 'base64' as const,
|
|
contentType: att.contentType,
|
|
}));
|
|
|
|
console.log(`[SMTP] Nombre de pièces jointes préparées pour nodemailer: ${attachments?.length || 0}`);
|
|
|
|
// Envoyer l'email
|
|
const mailOptions = {
|
|
from: `${config.fromName} <${config.fromEmail}>`,
|
|
to: params.to,
|
|
subject: params.subject,
|
|
html: params.html,
|
|
attachments: attachments,
|
|
};
|
|
|
|
console.log(`[SMTP] Envoi de l'email avec ${mailOptions.attachments?.length || 0} pièce(s) jointe(s)`);
|
|
const info = await transporter.sendMail(mailOptions);
|
|
|
|
console.log('[Email] Email envoyé via SMTP:', info.messageId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('[Email] Erreur lors de l\'envoi via SMTP:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Teste la connexion SMTP
|
|
*/
|
|
export async function testSMTPConnection(config: SMTPConfig): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const transporter = createTransporter(config);
|
|
|
|
// Vérifier la connexion
|
|
await transporter.verify();
|
|
|
|
return {
|
|
success: true,
|
|
message: 'Connexion SMTP réussie',
|
|
};
|
|
} catch (error) {
|
|
console.error('[Email] Erreur de connexion SMTP:', error);
|
|
return {
|
|
success: false,
|
|
message: error instanceof Error ? error.message : 'Erreur de connexion SMTP',
|
|
};
|
|
}
|
|
}
|