diff --git a/apps/api/.env.example b/apps/api/.env.example index ee79242..1f50f85 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -12,9 +12,9 @@ NODE_ENV=development SUPABASE_URL=https://tu-supabase.tudominio.com SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... -# Resend — servicio de email -# Crear cuenta en https://resend.com y configurar dominio -RESEND_API_KEY=re_... +# n8n — relé de email vía webhook (n8n se encarga de enviar por Gmail/SMTP) +# La URL es la del webhook configurado en el workflow de n8n. +N8N_EMAIL_WEBHOOK_URL=https://n8n.tudominio.com/webhook/naturcalabacera-email EMAIL_FROM=Naturcalabacera # Destinatarios de notificaciones (parametrizables, sin hardcodear) diff --git a/apps/api/src/config/env.ts b/apps/api/src/config/env.ts index b25325c..213374a 100644 --- a/apps/api/src/config/env.ts +++ b/apps/api/src/config/env.ts @@ -22,8 +22,8 @@ export const env = { SUPABASE_URL: required('SUPABASE_URL'), SUPABASE_SERVICE_ROLE_KEY: required('SUPABASE_SERVICE_ROLE_KEY'), - // Email — Resend - RESEND_API_KEY: required('RESEND_API_KEY'), + // Email — n8n webhook (relé a Gmail) + N8N_EMAIL_WEBHOOK_URL: required('N8N_EMAIL_WEBHOOK_URL'), EMAIL_FROM: optional('EMAIL_FROM', 'Naturcalabacera '), // Destinatarios de notificaciones (configurables, sin hardcodear) diff --git a/apps/api/src/services/email.ts b/apps/api/src/services/email.ts index c7fe816..5424e38 100644 --- a/apps/api/src/services/email.ts +++ b/apps/api/src/services/email.ts @@ -7,40 +7,34 @@ interface SendEmailOptions { replyTo?: string; } -interface ResendResponse { - id?: string; - error?: { message: string; name: string }; -} - /** - * Envía un email usando la API de Resend. - * Docs: https://resend.com/docs/api-reference/emails/send-email + * Envía un email a través del webhook de n8n. + * El workflow de n8n recibe { to, subject, html } y lo envía vía Gmail. */ export async function sendEmail(options: SendEmailOptions): Promise<{ success: boolean; id?: string; error?: string }> { try { - const res = await fetch('https://api.resend.com/emails', { + const to = Array.isArray(options.to) ? options.to.join(', ') : options.to; + + const res = await fetch(env.N8N_EMAIL_WEBHOOK_URL, { method: 'POST', - headers: { - 'Authorization': `Bearer ${env.RESEND_API_KEY}`, - 'Content-Type': 'application/json', - }, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - from: env.EMAIL_FROM, - to: Array.isArray(options.to) ? options.to : [options.to], + to, subject: options.subject, html: options.html, - ...(options.replyTo && { reply_to: options.replyTo }), + from: env.EMAIL_FROM, + replyTo: options.replyTo, }), }); - const data = await res.json() as ResendResponse; - - if (!res.ok || data.error) { - const errorMsg = data.error?.message ?? `HTTP ${res.status}`; + if (!res.ok) { + const text = await res.text().catch(() => ''); + const errorMsg = `HTTP ${res.status}${text ? ` — ${text.slice(0, 200)}` : ''}`; console.error('[email] Error al enviar:', errorMsg); return { success: false, error: errorMsg }; } + const data = await res.json().catch(() => ({})) as { id?: string }; return { success: true, id: data.id }; } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Error desconocido'; diff --git a/n8n-workflows/naturcalabacera-email-relay.json b/n8n-workflows/naturcalabacera-email-relay.json new file mode 100644 index 0000000..80666bc --- /dev/null +++ b/n8n-workflows/naturcalabacera-email-relay.json @@ -0,0 +1,71 @@ +{ + "name": "Naturcalabacera - Email Relay", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "naturcalabacera-email", + "responseMode": "responseNode", + "options": {} + }, + "id": "webhook-naturcalabacera", + "name": "Webhook (POST email)", + "type": "n8n-nodes-base.webhook", + "typeVersion": 2, + "position": [240, 300] + }, + { + "parameters": { + "sendTo": "={{ $json.body.to }}", + "subject": "={{ $json.body.subject }}", + "emailType": "html", + "message": "={{ $json.body.html }}", + "options": {} + }, + "id": "gmail-send", + "name": "Gmail — Enviar", + "type": "n8n-nodes-base.gmail", + "typeVersion": 2.1, + "position": [520, 300] + }, + { + "parameters": { + "respondWith": "json", + "responseBody": "={{ { success: true, id: $json.id } }}", + "options": {} + }, + "id": "respond-ok", + "name": "Responder OK", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1.1, + "position": [800, 300] + } + ], + "connections": { + "Webhook (POST email)": { + "main": [ + [ + { + "node": "Gmail — Enviar", + "type": "main", + "index": 0 + } + ] + ] + }, + "Gmail — Enviar": { + "main": [ + [ + { + "node": "Responder OK", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "settings": { + "executionOrder": "v1" + } +}