n8n Reportes Automáticos: Genera PDFs y Envíalos por Email

N8n reportes automáticos PDF es uno de los usos más prácticos de n8n. Los reportes automáticos con n8n eliminan horas de trabajo manual cada semana. En lugar de exportar datos manualmente, formatearlos en un documento y enviarlo por email, n8n hace todo esto de forma automática y programada. En esta guía aprenderás a construir un sistema de generación y envío de informes en PDF.

Casos de uso para reportes automáticos

  • Informe semanal de ventas para el equipo directivo
  • Reporte mensual de marketing con métricas de campañas
  • Dashboard de KPIs enviado cada lunes a los gerentes
  • Informe de errores diario para el equipo técnico
  • Estado de proyectos semanal para clientes

Arquitectura del sistema de reportes

Schedule Trigger (hora y frecuencia definidas)
  → Recopilar datos (Sheets, DB, APIs)
  → Procesar y calcular métricas (Code node)
  → Generar HTML del informe
  → Convertir a PDF
  → Enviar por email a la lista de destinatarios
  → Guardar copia en Drive

Paso 1: Recopilar los datos

Desde Google Sheets

Google Sheets — Get All Rows
  (selecciona el rango o toda la hoja con los datos)

Desde una base de datos SQL

MySQL/Postgres — Execute Query:
SELECT
  DATE_TRUNC('week', fecha) as semana,
  COUNT(*) as pedidos,
  SUM(importe) as ingresos,
  AVG(importe) as ticket_medio
FROM pedidos
WHERE fecha >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY 1
ORDER BY 1

Desde múltiples fuentes en paralelo

n8n puede ejecutar varios nodos en paralelo y luego combinar los resultados:

Schedule Trigger
  → [Rama 1] Google Analytics — métricas web
  → [Rama 2] HubSpot — leads de la semana
  → [Rama 3] Stripe — ingresos
  → Merge — combina los tres resultados
  → Code — calcula el informe

Paso 2: Calcular métricas en el nodo Code

const data = $input.all();

// Calcular variación respecto a la semana anterior
const semanaActual = data.filter(d => d.json.periodo === 'actual');
const semanaAnterior = data.filter(d => d.json.periodo === 'anterior');

const variacion = semanaActual.length > 0 && semanaAnterior.length > 0
  ? ((semanaActual[0].json.ingresos - semanaAnterior[0].json.ingresos) / semanaAnterior[0].json.ingresos * 100).toFixed(1)
  : 0;

return [{
  ingresos_semana: semanaActual[0]?.json.ingresos || 0,
  pedidos_semana: semanaActual[0]?.json.pedidos || 0,
  variacion_ingresos: variacion,
  top_producto: semanaActual[0]?.json.top_producto || 'N/A',
  fecha_generacion: new Date().toLocaleDateString('es-ES', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })
}];

Paso 3: Generar el HTML del informe

// Nodo Code: genera el HTML del reporte
const d = $input.first().json;

const variacionColor = parseFloat(d.variacion_ingresos) >= 0 ? '#27ae60' : '#e74c3c';
const variacionIcon = parseFloat(d.variacion_ingresos) >= 0 ? '▲' : '▼';

const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  body { font-family: 'Segoe UI', Arial, sans-serif; background: #f5f6fa; margin: 0; padding: 20px; }
  .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 8px; overflow: hidden; }
  .header { background: #2c3e50; color: white; padding: 30px; }
  .header h1 { margin: 0; font-size: 24px; }
  .header p { margin: 5px 0 0; opacity: 0.8; }
  .metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; padding: 30px; }
  .metric { background: #f8f9fa; border-radius: 8px; padding: 20px; text-align: center; }
  .metric .value { font-size: 32px; font-weight: bold; color: #2c3e50; }
  .metric .label { font-size: 12px; color: #7f8c8d; margin-top: 5px; text-transform: uppercase; }
  .variacion { color: ${variacionColor}; font-size: 14px; margin-top: 5px; }
  .footer { padding: 20px 30px; background: #f8f9fa; color: #7f8c8d; font-size: 12px; }
</style>
</head>
<body>
  <div class="container">
    <div class="header">
      <h1>📊 Informe Semanal de Ventas</h1>
      <p>Generado el ${d.fecha_generacion}</p>
    </div>
    <div class="metrics">
      <div class="metric">
        <div class="value">${d.ingresos_semana}€</div>
        <div class="label">Ingresos</div>
        <div class="variacion">${variacionIcon} ${Math.abs(d.variacion_ingresos)}% vs semana anterior</div>
      </div>
      <div class="metric">
        <div class="value">${d.pedidos_semana}</div>
        <div class="label">Pedidos</div>
      </div>
      <div class="metric">
        <div class="value">${d.top_producto}</div>
        <div class="label">Producto estrella</div>
      </div>
    </div>
    <div class="footer">
      Informe generado automáticamente por n8n • ${new Date().toISOString()}
    </div>
  </div>
</body>
</html>`;

return [{ html }];

Paso 4: Convertir HTML a PDF

Opción A: PDFShift (recomendado, tiene plan gratuito)

HTTP Request:
URL: https://api.pdfshift.io/v3/convert/pdf
Method: POST
Auth: Basic (API key como username, vacío como password)
Body JSON: {
  "source": "{{ $json.html }}",
  "landscape": false,
  "use_print": true,
  "format": "A4"
}
Response Format: File

Opción B: Puppeteer en servidor propio

Si tienes n8n en un VPS, puedes ejecutar Puppeteer con el nodo Execute Command:

node -e "
const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch({args: ['--no-sandbox']});
  const page = await browser.newPage();
  await page.setContent(process.argv[1]);
  await page.pdf({path: '/tmp/report.pdf', format: 'A4'});
  await browser.close();
})();
" "{{ $json.html }}"

Paso 5: Enviar el PDF por email

Gmail — Send Email:
  To: direccion1@empresa.com, direccion2@empresa.com
  Subject: Informe Semanal de Ventas — Semana {{ $now.toFormat('W') }}
  Body: <p>Adjunto encontrarás el informe de ventas de esta semana.</p>
  Attachment Binary: el PDF generado

Para enviar a una lista variable de destinatarios, guárdalos en Google Sheets y úsalos dinámicamente:

{{ $('Google Sheets').all().map(r => r.json.email).join(',') }}

Variante: Informe como email HTML (sin PDF)

Si prefieres enviar el informe directamente en el cuerpo del email:

Gmail:
  HTML Body: {{ $json.html }}

Es más sencillo y el destinatario lo ve directamente sin descargar nada.

Conclusión

Los reportes automáticos con n8n eliminan horas de trabajo manual y garantizan que los datos correctos lleguen a las personas correctas en el momento correcto. Con datos de Google Sheets, MySQL o APIs, n8n puede generar informes profesionales en PDF de forma completamente autónoma. Una vez configurado, el sistema funciona solo sin que nadie tenga que recordar ejecutarlo.