6066f27ba0
Menu Calendario (Mes/Semana/Dia/Agenda) para agendar reuniones con participantes internos y externos, RSVP, vinculo a proyecto, vencimientos de actividades, invitaciones iCalendar por correo, recurrencia con excepciones, recordatorios in-app y aviso de choques. Migracion 034_meetings.sql. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
32 lines
1.3 KiB
JavaScript
32 lines
1.3 KiB
JavaScript
import nodemailer from 'nodemailer';
|
|
import { getSmtpConfigInternal } from '../modules/settings/service.js';
|
|
|
|
// Degradacion a modo dev cuando el SMTP no esta configurado (regla del orquestador): en vez de
|
|
// fallar, se loguea el contenido/enlace y el flujo que llamo a esto sigue funcionando.
|
|
export async function sendMail({ to, subject, html, icalEvent }) {
|
|
try {
|
|
const config = await getSmtpConfigInternal();
|
|
|
|
if (!config) {
|
|
console.log(`[mail:dev] to=${to} subject="${subject}"\n${html}${icalEvent?.content ? `\n[icalEvent]\n${icalEvent.content}` : ''}`);
|
|
return { sent: false, dev: true };
|
|
}
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
host: config.host,
|
|
port: config.port,
|
|
secure: false,
|
|
requireTLS: true,
|
|
auth: { user: config.user, pass: config.pass },
|
|
});
|
|
|
|
// Nunca dejar que un fallo de envio (SMTP mal configurado, host caido) tumbe al que llama —
|
|
// critico para forgot-password, que siempre debe responder generico sin importar el resultado.
|
|
await transporter.sendMail({ from: config.from, to, subject, html, ...(icalEvent ? { icalEvent } : {}) });
|
|
return { sent: true, dev: false };
|
|
} catch (err) {
|
|
console.error('[mail:error]', err.message);
|
|
return { sent: false, dev: false, error: err.message };
|
|
}
|
|
}
|