{
  "name": "Daily email digest of all failed n8n executions",
  "nodes": [
    {
      "parameters": {
        "content": "## 📬 Daily failure digest\n\nEvery morning at 08:00: one email listing every failed execution from the last 24h, grouped per workflow with counts and last-failure time. No failures → no email.\n\n### Setup (~4 minutes)\n1. **n8n API credential** on both n8n nodes (n8n → Settings → *n8n API* → create key; base URL = your instance URL).\n2. **SMTP credential** on **Send digest email**.\n3. **Config node:** set the from/to addresses (and the digest window, if you want something other than 24h).\n4. Save & **activate**.\n\n### Good to know\n- Scans the last 100 executions; very busy instance → raise the limit in *Get recent executions*.\n- Prefer a \"still alive\" email even on clean days? In *Build digest*, replace `return []` with a heartbeat item.\n\n---\n🩺 Want this without the plumbing — plus instant alerts the moment things break, volume-anomaly detection and Make.com support? **WentQuiet** → https://wentquiet.com?ref=n8n-template. Founding pricing is open.",
        "width": 440,
        "height": 620
      },
      "id": "sticky-setup-3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-300, -60]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * *"
            }
          ]
        }
      },
      "id": "schedule-3",
      "name": "Every morning 08:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [220, 160]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-window",
              "name": "digestHours",
              "value": 24,
              "type": "number"
            },
            {
              "id": "cfg-to",
              "name": "toEmail",
              "value": "you@example.com",
              "type": "string"
            },
            {
              "id": "cfg-from",
              "name": "fromEmail",
              "value": "n8n@yourdomain.com",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "config-3",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [420, 160]
    },
    {
      "parameters": {
        "resource": "execution",
        "operation": "getAll",
        "returnAll": false,
        "limit": 100,
        "filters": {}
      },
      "id": "get-execs-3",
      "name": "Get recent executions",
      "type": "n8n-nodes-base.n8n",
      "typeVersion": 1,
      "position": [620, 160]
    },
    {
      "parameters": {
        "resource": "workflow",
        "operation": "getAll",
        "returnAll": true,
        "filters": {}
      },
      "id": "get-workflows-3",
      "name": "Get workflows",
      "type": "n8n-nodes-base.n8n",
      "typeVersion": 1,
      "position": [820, 160],
      "executeOnce": true
    },
    {
      "parameters": {
        "jsCode": "const cfg = $('Config').first().json;\nconst hours = Number(cfg.digestHours) || 24;\nconst since = Date.now() - hours * 3600 * 1000;\nconst execs = $('Get recent executions').all().map(i => i.json);\nconst wfs = $input.all().map(i => i.json);\nconst names = Object.fromEntries(wfs.map(w => [String(w.id), w.name]));\nconst failed = execs.filter(e => {\n  const isError = e.status ? e.status === 'error' : (e.finished === false && e.stoppedAt);\n  return isError && new Date(e.startedAt).getTime() >= since;\n});\nif (failed.length === 0) return []; // no email on quiet days — swap for a heartbeat item if you prefer\nconst byWf = {};\nfor (const e of failed) {\n  const key = String(e.workflowId);\n  byWf[key] = byWf[key] || { name: names[key] || `Workflow ${key}`, count: 0, last: e.startedAt };\n  byWf[key].count++;\n  if (e.startedAt > byWf[key].last) byWf[key].last = e.startedAt;\n}\nconst rows = Object.values(byWf).sort((a, b) => b.count - a.count)\n  .map(w => `<tr><td style=\"padding:4px 12px;\">${w.name}</td><td style=\"padding:4px 12px;text-align:center;\">${w.count}</td><td style=\"padding:4px 12px;\">${new Date(w.last).toLocaleString()}</td></tr>`)\n  .join('');\nconst html = `<h2>n8n failure digest — last ${hours}h</h2>\n<p><b>${failed.length}</b> failed execution(s) across <b>${Object.keys(byWf).length}</b> workflow(s).</p>\n<table border=\"1\" style=\"border-collapse:collapse;\"><tr><th style=\"padding:4px 12px;\">Workflow</th><th style=\"padding:4px 12px;\">Failures</th><th style=\"padding:4px 12px;\">Last failure</th></tr>${rows}</table>\n<p style=\"color:#888;font-size:12px;\">Sent by your n8n daily-digest workflow. Only the last 100 executions are scanned — busy instance? Raise the limit.</p>`;\nreturn [{ json: { subject: `⚠️ n8n: ${failed.length} failed execution(s) in the last ${hours}h`, html } }];"
      },
      "id": "build-digest-3",
      "name": "Build digest",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1020, 160]
    },
    {
      "parameters": {
        "fromEmail": "={{ $('Config').first().json.fromEmail }}",
        "toEmail": "={{ $('Config').first().json.toEmail }}",
        "subject": "={{ $json.subject }}",
        "emailFormat": "html",
        "html": "={{ $json.html }}",
        "options": {}
      },
      "id": "send-email-3",
      "name": "Send digest email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [1220, 160]
    }
  ],
  "connections": {
    "Every morning 08:00": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Get recent executions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get recent executions": {
      "main": [
        [
          {
            "node": "Get workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get workflows": {
      "main": [
        [
          {
            "node": "Build digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build digest": {
      "main": [
        [
          {
            "node": "Send digest email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
