## Bug Fixes ### Note Card Actions - Fix broken size change functionality (missing state declaration) - Implement React 19 useOptimistic for instant UI feedback - Add startTransition for non-blocking updates - Ensure smooth animations without page refresh - All note actions now work: pin, archive, color, size, checklist ### Markdown LaTeX Rendering - Add remark-math and rehype-katex plugins - Support inline equations with dollar sign syntax - Support block equations with double dollar sign syntax - Import KaTeX CSS for proper styling - Equations now render correctly instead of showing raw LaTeX ## Technical Details - Replace undefined currentNote references with optimistic state - Add optimistic updates before server actions for instant feedback - Use router.refresh() in transitions for smart cache invalidation - Install remark-math, rehype-katex, and katex packages ## Testing - Build passes successfully with no TypeScript errors - Dev server hot-reloads changes correctly
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
import nodemailer from 'nodemailer';
|
|
import { getSystemConfig } from './config';
|
|
|
|
interface MailOptions {
|
|
to: string;
|
|
subject: string;
|
|
html: string;
|
|
}
|
|
|
|
export async function sendEmail({ to, subject, html }: MailOptions) {
|
|
const config = await getSystemConfig();
|
|
|
|
const host = config.SMTP_HOST || process.env.SMTP_HOST;
|
|
const port = parseInt(config.SMTP_PORT || process.env.SMTP_PORT || '587');
|
|
const user = (config.SMTP_USER || process.env.SMTP_USER || '').trim();
|
|
const pass = (config.SMTP_PASS || process.env.SMTP_PASS || '').trim();
|
|
const from = config.SMTP_FROM || process.env.SMTP_FROM || 'noreply@memento.app';
|
|
|
|
// Options de sécurité
|
|
const forceSecure = config.SMTP_SECURE === 'true'; // Forcé par l'admin
|
|
const isPort465 = port === 465;
|
|
// Si secure n'est pas forcé, on déduit du port (465 = secure, autres = starttls)
|
|
const secure = forceSecure || isPort465;
|
|
|
|
const ignoreCerts = config.SMTP_IGNORE_CERT === 'true';
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
host: host || undefined,
|
|
port: port || undefined,
|
|
secure: secure || false,
|
|
auth: { user, pass },
|
|
// Force IPv4 pour éviter les problèmes de résolution DNS/Docker
|
|
family: 4,
|
|
// Force AUTH LOGIN pour meilleure compatibilité (Mailcow, Exchange) vs PLAIN par défaut
|
|
authMethod: 'LOGIN',
|
|
// Timeout généreux
|
|
connectionTimeout: 10000,
|
|
tls: {
|
|
// Si on ignore les certs, on autorise tout.
|
|
// Sinon on laisse les défauts stricts de Node.
|
|
rejectUnauthorized: !ignoreCerts,
|
|
// Compatibilité vieux serveurs si besoin (optionnel, activé si ignoreCerts pour maximiser les chances)
|
|
ciphers: ignoreCerts ? 'SSLv3' : undefined
|
|
}
|
|
} as any);
|
|
|
|
try {
|
|
await transporter.verify();
|
|
|
|
const info = await transporter.sendMail({
|
|
from: `"Memento App" <${from}>`,
|
|
to,
|
|
subject,
|
|
html,
|
|
});
|
|
|
|
return { success: true, messageId: info.messageId };
|
|
} catch (error: any) {
|
|
console.error("❌ Erreur SMTP:", error);
|
|
return {
|
|
success: false,
|
|
error: `Erreur envoi: ${error.message} (Code: ${error.code})`
|
|
};
|
|
}
|
|
} |