{
  "id": "2gzPkMROTVEttKpn",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "N8N-WP Newsletter",
  "tags": [
    {
      "id": "DrJfO3FIj4VGV9fL",
      "name": "Newsletter",
      "createdAt": "2025-06-14T22:02:24.176Z",
      "updatedAt": "2025-06-14T22:02:24.176Z"
    },
    {
      "id": "p7d66niWAG5ijZY7",
      "name": "AI",
      "createdAt": "2025-10-19T20:35:12.051Z",
      "updatedAt": "2026-03-22T18:22:29.537Z"
    },
    {
      "id": "858ibTiQUPzCapCC",
      "name": "Wordpress",
      "createdAt": "2025-05-16T19:06:52.526Z",
      "updatedAt": "2026-03-22T18:24:44.555Z"
    }
  ],
  "nodes": [
    {
      "id": "866859d4-61fe-4f26-b0eb-799ecdbd1131",
      "name": "\ud83d\udccb Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        -416
      ],
      "parameters": {
        "width": 460,
        "height": 848,
        "content": "## Blog Post Newsletter \u2014 Weekly Digest\n\nAutomatically fetches the latest posts from your WordPress blog, uses AI to generate engaging summaries, then emails the newsletter to your subscriber list.\n\n### How it works\n1. **Schedule Trigger** fires every Monday at 10 AM\n2. **Fetch WP Posts** pulls posts published in the last 7 days (up to 20) with embedded featured media via the WordPress REST API\n3. **Process Posts** normalises the raw API data into clean article objects with titles, excerpts, images, and categories\n4. **AI Content Agent** (GPT-4o) rewrites each article into a polished 3\u20135 sentence summary and produces an overview intro\n5. **Format HTML Email** renders the summaries into a responsive, branded HTML newsletter\n6. **Fetch Subscribers** retrieves your mailing list from a custom WordPress endpoint\n7. **Check Valid Email** filters out any records with missing email addresses\n8. **Send Newsletter** delivers the email via Gmail to each subscriber\n\n### Setup\n- Add your **WordPress site URL** in the *Fetch WP Posts* node\n- Configure your **Google Sheet** credential for the *Get Subscribers* node and update the Google Sheets information\n- Set your **OpenAI** credential on the *LLM \u2014 GPT-4o* sub-node\n- Set your **Gmail OAuth2** credential on the *Send Newsletter* node\n- Review the CTA link in the *Format HTML Email* Code node\n\n### Customization\n- Change the schedule day/time in the *Weekly Schedule* node\n- Adjust `per_page` (default 20) and `days` window (default 7) in *Fetch WP Posts*\n- Edit brand colors, logo URL, and footer links inside the *Format HTML Email* Code node"
      },
      "typeVersion": 1
    },
    {
      "id": "c0373246-56f7-4666-9eb7-0a40a68e251b",
      "name": "Section \u2014 Fetch & Process",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -416
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 280,
        "content": "## 1 \u00b7 Fetch & Process Posts\nRetrieves WordPress posts published in the last 7 days (with embedded featured media), then normalises the raw API response into clean article objects ready for AI summarisation."
      },
      "typeVersion": 1
    },
    {
      "id": "4a95e2e5-2bf7-4573-bccb-ee07f12af157",
      "name": "Section \u2014 AI Summarisation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -416
      ],
      "parameters": {
        "color": 7,
        "width": 456,
        "height": 456,
        "content": "## 2 \u00b7 AI Content Generation\nThe AI Agent uses GPT-4o to write a 3\u20135 sentence summary for each article and produce a short weekly overview. The HTML Code node then renders everything into a responsive email template."
      },
      "typeVersion": 1
    },
    {
      "id": "4c20afeb-35b4-4a06-bd36-f4aa2e826a7d",
      "name": "Section \u2014 Subscriber Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        -416
      ],
      "parameters": {
        "color": 7,
        "width": 588,
        "height": 280,
        "content": "## 3 \u00b7 Subscriber Delivery\nFetches your subscriber list from a Google Sheets workbook. Each record is validated for a non-empty email address before the newsletter is delivered via Gmail. Skipped records (missing email) exit quietly."
      },
      "typeVersion": 1
    },
    {
      "id": "eabb4506-2b52-47d8-a636-2d22e5230bcc",
      "name": "\u26a0\ufe0f Community / LangChain Nodes",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -64
      ],
      "parameters": {
        "color": 3,
        "width": 340,
        "height": 140,
        "content": "\u26a0\ufe0f **Self-hosted n8n required**\n\nThis workflow uses **@n8n/n8n-nodes-langchain** (AI Agent + OpenAI Chat Model). These are bundled with self-hosted n8n but may not be available on all cloud plans. Verify your plan before deploying."
      },
      "typeVersion": 1
    },
    {
      "id": "ec44e757-629b-4195-b1e2-9b6715132d4b",
      "name": "Weekly Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        16,
        -288
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 10
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "cb73ccc2-b98d-4b34-bb2b-9233e7423743",
      "name": "Fetch WP Posts",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        192,
        -288
      ],
      "parameters": {
        "url": "https://YOUR-WORDPRESS-SITE.com/wp-json/wp/v2/posts",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "_embed",
              "value": "wp:featuredmedia"
            },
            {
              "name": "after",
              "value": "={{ $now.minus({ days: 7 }).toISO() }}"
            },
            {
              "name": "per_page",
              "value": "20"
            },
            {
              "name": "orderby",
              "value": "date"
            },
            {
              "name": "order",
              "value": "desc"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "14ae5a50-eab2-4b63-a356-5e1bd2d49a9f",
      "name": "Process Posts",
      "type": "n8n-nodes-base.code",
      "position": [
        352,
        -288
      ],
      "parameters": {
        "jsCode": "// Process WordPress posts with embedded featured media\n// Mode: Run Once for All Items \u2014 aggregates all posts into single output\n// Returns structured articles with imageUrl for newsletter thumbnails\n\nconst inputItems = $input.all();\nlet posts = [];\n\nfor (const item of inputItems) {\n  const data = item.json;\n  if (Array.isArray(data)) {\n    posts.push(...data);\n  } else if (data && typeof data === 'object') {\n    posts.push(data);\n  }\n}\n\nlet articles = [];\n\nconst toISO = (ts) => {\n  if (!ts) return new Date().toISOString();\n  try {\n    if (typeof ts === 'number') return new Date(ts < 1e12 ? ts * 1000 : ts).toISOString();\n    return new Date(ts).toISOString();\n  } catch { return new Date().toISOString(); }\n};\n\nconst stripTags = (html) => {\n  if (!html) return '';\n  return String(html)\n    .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n    .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n    .replace(/<[^>]+>/g, '')\n    .replace(/\\s+/g, ' ')\n    .trim();\n};\n\nconst decodeHTMLEntities = (text) => {\n  if (!text) return '';\n  const map = { '&amp;':'&','&lt;':'<','&gt;':'>','&quot;':'\"','&#39;':\"'\",'&nbsp;':' ' };\n  return text\n    .replace(/(&amp;|&lt;|&gt;|&quot;|&#39;|&nbsp;)/g, m => map[m])\n    .replace(/(\\d+);/g, (_, n) => String.fromCharCode(parseInt(n,10)))\n    .replace(/([0-9a-fA-F]+);/g, (_, n) => String.fromCharCode(parseInt(n,16)));\n};\n\nconst clean = (s) => decodeHTMLEntities(stripTags(s || ''));\n\nconst getImageUrl = (post) => {\n  try {\n    const embedded = post._embedded?.['wp:featuredmedia'];\n    if (embedded && embedded[0]) {\n      const sizes = embedded[0].media_details?.sizes;\n      if (sizes) {\n        return sizes.medium_large?.source_url || sizes.medium?.source_url || sizes.thumbnail?.source_url || embedded[0].source_url || '';\n      }\n      return embedded[0].source_url || '';\n    }\n    if (post.jetpack_featured_media_url) return post.jetpack_featured_media_url;\n    if (post.featured_media_src_url) return post.featured_media_src_url;\n    if (post.yoast_head_json?.og_image?.[0]?.url) return post.yoast_head_json.og_image[0].url;\n    return '';\n  } catch { return ''; }\n};\n\nconst getCategories = (post) => {\n  const categories = [];\n  try {\n    if (post._embedded?.['wp:term']) {\n      post._embedded['wp:term'].flat().forEach(t => {\n        if (t.taxonomy === 'category' && t.name) categories.push(decodeHTMLEntities(t.name));\n      });\n    }\n  } catch {}\n  return categories.length ? categories : ['Technology'];\n};\n\nfor (const p of posts) {\n  const titleRaw = p?.title?.rendered ?? p?.title ?? '';\n  const url = p?.link ?? p?.guid?.rendered ?? p?.guid ?? '';\n  if (!titleRaw || !url) continue;\n\n  const excerptRaw = p?.excerpt?.rendered ?? '';\n  const contentRaw = p?.content?.rendered ?? '';\n  const publishedAt = toISO(p?.date_gmt ?? p?.date);\n  const imageUrl = getImageUrl(p);\n  const categories = getCategories(p);\n\n  articles.push({\n    title: clean(titleRaw),\n    description: clean(excerptRaw || contentRaw || titleRaw).slice(0, 500),\n    url,\n    imageUrl,\n    source: 'WordPress',\n    publishedAt,\n    categories,\n    score: 0,\n  });\n}\n\nconst seen = new Set();\narticles = articles.filter(a => {\n  const key = a.url || 't:' + a.title;\n  if (seen.has(key)) return false;\n  seen.add(key);\n  return true;\n});\n\narticles.sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime());\narticles = articles.slice(0, 12);\n\nreturn [{ json: { articles, totalResults: articles.length, sources: ['WordPress'] } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "e96b1eb2-a24f-44e9-af9b-7e6ef88ab8c8",
      "name": "LLM \u2014 GPT-4o",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        512,
        -96
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o"
        },
        "options": {
          "maxTokens": 4000,
          "temperature": 0.7
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "b3ef1468-3c0a-4894-929a-a3fc7e76c25d",
      "name": "AI \u2014 Generate Summaries",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        512,
        -288
      ],
      "parameters": {
        "text": "=Based on the following recent blog articles, create concise summaries of each article:\n\nNews Data: {{ JSON.stringify($json.articles?.slice(0, 12)) }}\n\nRequirements:\n- Write 3\u20135 sentence professional summaries for each article\n- Clearly explain the main topic and practical relevance for readers\n- Use plain, engaging language that is easy to scan\n- Include the article's title as the headline\n- IMPORTANT: Copy the exact 'url' and 'imageUrl' fields from the input data \u2014 do not modify these URLs\n- Include the category from the input data\n\nReturn as JSON with this exact structure:\n{\n  \"articles\": [\n    {\n      \"headline\": \"Article Title Here\",\n      \"summary\": \"3-5 sentence summary...\",\n      \"url\": \"https://example.com/post-slug\",\n      \"imageUrl\": \"https://example.com/image.jpg\",\n      \"category\": \"Category Name\",\n      \"date\": \"2025-01-01\",\n      \"word_count\": 150\n    }\n  ],\n  \"newsletter_date\": \"{{ $now.format('MMMM d, yyyy') }}\",\n  \"overview\": \"Brief overview of this week's key themes (2-3 sentences)\"\n}\n\nIMPORTANT: The imageUrl must be copied exactly as provided in the input \u2014 these are required for newsletter thumbnails.",
        "options": {
          "systemMessage": "You are an expert technology journalist. Your role is to transform WordPress blog posts into short, professional summaries that readers can quickly scan and understand. Write in a clear, engaging, and concise style that highlights the key message and practical relevance of each article.\n\nCRITICAL: Always preserve the exact 'url' and 'imageUrl' values from the input data \u2014 never modify, summarise, or omit these fields. They are essential for the newsletter layout."
        },
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "f6df18c8-c9fa-4555-b4b4-a653b5a92cc3",
      "name": "Format HTML Email",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        -288
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// FORMAT NEWSLETTER HTML\n// Renders AI summaries into a branded HTML email\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// CUSTOMISE: Update SITE_NAME, SITE_URL, LOGO_URL,\n//            BRAND_NAVY, BRAND_ORANGE, CTA_URL, and CTA_TEXT below.\n\nconst SITE_NAME    = 'YOUR COMPANY NAME';        // \u2190 customise\nconst SITE_URL     = 'https://YOUR-SITE.com';    // \u2190 customise\nconst LOGO_URL     = 'https://YOUR-SITE.com/wp-content/uploads/logo.png'; // \u2190 customise\nconst BRAND_NAVY   = '#002657';\nconst BRAND_ORANGE = '#FA4616';\nconst CTA_URL      = 'https://YOUR-SITE.com/contact'; // \u2190 customise\nconst CTA_TEXT     = 'Schedule a Consultation';        // \u2190 customise\n\n// \u2500\u2500\u2500 Parse AI output \u2500\u2500\u2500\nconst aiResponse = $json.output || $json.data || '';\nlet newsletterData;\n\nfunction safeJSONStringParse(s) {\n  if (!s) return null;\n  try {\n    const match = s.match(/\\{[\\s\\S]*\\}/);\n    return match ? JSON.parse(match[0]) : null;\n  } catch { return null; }\n}\n\nnewsletterData = safeJSONStringParse(aiResponse);\n\nif (!newsletterData || !Array.isArray(newsletterData.articles)) {\n  newsletterData = {\n    articles: [{\n      headline: 'This Week on Our Blog',\n      summary: (aiResponse || 'No AI summary available.').toString().slice(0, 600) + '\u2026',\n      url: '',\n      imageUrl: '',\n      category: 'Technology',\n      date: '',\n      word_count: 0,\n    }],\n    newsletter_date: new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }),\n    overview: 'Highlights from our latest blog posts.',\n  };\n}\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\nfunction formatDateHuman(input) {\n  if (!input) return '';\n  const d = new Date(input);\n  if (isNaN(d.getTime())) return String(input);\n  return d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n}\n\nfunction renderArticleCard(a, index) {\n  const hasImage = a.imageUrl && a.imageUrl.trim() !== '';\n  const cat = a.category || 'Technology';\n  const dateTxt = formatDateHuman(a.date || a.publishedAt || a.published_at || '');\n  const metaParts = [cat, dateTxt].filter(Boolean).join(' \u2022 ');\n  const imageUrl = hasImage ? a.imageUrl : LOGO_URL;\n  const summary = (a.summary || '').toString().replace(/\\n+/g, ' ').trim();\n\n  return `\n  <tr>\n    <td style=\"padding: 0 0 24px 0;\">\n      <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"background:#ffffff;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden;\">\n        <tr>\n          <td align=\"center\" style=\"padding:0;\">\n            <a href=\"${a.url || '#'}\" target=\"_blank\" style=\"display:block;text-decoration:none;\">\n              <div style=\"width:100%;height:156px;overflow:hidden;\">\n                <img src=\"${imageUrl}\" width=\"100%\" alt=\"${(a.headline||'Article').replace(/\"/g,'&quot;')}\" style=\"display:block;width:100%;height:208px;object-fit:cover;object-position:center center;border:0;margin-top:-26px;\">\n              </div>\n            </a>\n          </td>\n        </tr>\n        <tr>\n          <td style=\"padding:20px;\">\n            <div style=\"font-size:12px;font-weight:600;color:${BRAND_ORANGE};text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px;\">${metaParts}</div>\n            <a href=\"${a.url||'#'}\" target=\"_blank\" style=\"text-decoration:none;\">\n              <div style=\"font-size:20px;font-weight:700;color:#1e293b;line-height:1.3;margin-bottom:12px;\">${a.headline||'Untitled Article'}</div>\n            </a>\n            <div style=\"font-size:15px;color:#4b5563;line-height:1.7;margin-bottom:16px;\">${summary}</div>\n            ${a.url ? `<a href=\"${a.url}\" target=\"_blank\" style=\"font-size:14px;font-weight:600;color:#1d4ed8;text-decoration:none;\">Read full article &rarr;</a>` : ''}\n          </td>\n        </tr>\n      </table>\n    </td>\n  </tr>`;\n}\n\n// \u2500\u2500\u2500 Build HTML \u2500\u2500\u2500\nconst newsletterHtml = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"x-apple-disable-message-reformatting\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>${SITE_NAME} Weekly Digest \u2014 ${newsletterData.newsletter_date}</title>\n  <style>\n    img{border:0;outline:none;text-decoration:none;}\n    table{border-collapse:collapse!important;}\n    body,td{margin:0;padding:0;}\n    @media only screen and (max-width:600px){.container{width:100%!important;}.mobile-pad{padding:12px!important;}}\n  </style>\n</head>\n<body style=\"margin:0;padding:16px;background:#f1f5f9;font-family:Georgia,'Times New Roman',serif;line-height:1.6;color:#334155;\">\n  <center>\n    <table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100%\" style=\"max-width:680px;\">\n      <tr><td>\n        <table class=\"container\" role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100%\" style=\"max-width:680px;background:#ffffff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,0.08);\">\n\n          <!-- HEADER -->\n          <tr>\n            <td style=\"background:linear-gradient(135deg,${BRAND_NAVY} 0%,#003d7a 100%);padding:20px 24px 16px 24px;text-align:center;\">\n              <img src=\"${LOGO_URL}\" width=\"140\" alt=\"${SITE_NAME} Logo\" style=\"display:block;max-width:140px;height:auto;margin:0 auto;\">\n              <div style=\"font-size:26px;font-weight:bold;color:#ffffff;margin:12px 0 4px 0;letter-spacing:-0.5px;\">Weekly Digest</div>\n              <div style=\"font-size:14px;font-style:italic;color:#94a3b8;margin-bottom:6px;\">Your weekly roundup of the latest articles</div>\n              <div style=\"font-size:13px;color:#cbd5e1;font-weight:500;\">${newsletterData.newsletter_date}</div>\n            </td>\n          </tr>\n\n          <!-- OVERVIEW -->\n          <tr>\n            <td style=\"padding:16px 20px 12px 20px;\">\n              <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"background:linear-gradient(135deg,#f0f9ff 0%,#e0f2fe 100%);border-left:4px solid #0284c7;border-radius:0 8px 8px 0;\">\n                <tr><td style=\"padding:14px 20px;\">\n                  <div style=\"font-size:16px;font-weight:bold;color:#0369a1;margin-bottom:6px;\">\ud83d\udccb This Week's Overview</div>\n                  <div style=\"font-size:15px;color:#334155;line-height:1.6;\">${newsletterData.overview||'Explore our latest articles.'}</div>\n                </td></tr>\n              </table>\n            </td>\n          </tr>\n\n          <!-- ARTICLES -->\n          <tr>\n            <td style=\"padding:8px 20px 24px 20px;\">\n              <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n                ${newsletterData.articles.map((a,i) => renderArticleCard(a,i)).join('')}\n              </table>\n            </td>\n          </tr>\n\n          <!-- CTA -->\n          <tr>\n            <td align=\"center\" style=\"padding:0 20px 32px 20px;\">\n              <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n                <tr>\n                  <td style=\"background:${BRAND_NAVY};border-radius:8px;\">\n                    <a href=\"${CTA_URL}\" target=\"_blank\" style=\"display:inline-block;padding:14px 32px;color:#ffffff;font-size:15px;font-weight:bold;text-decoration:none;border-radius:8px;background:${BRAND_NAVY};\">${CTA_TEXT}</a>\n                  </td>\n                </tr>\n              </table>\n            </td>\n          </tr>\n\n          <!-- FOOTER -->\n          <tr>\n            <td style=\"background:#1e293b;padding:28px 24px;text-align:center;\">\n              <div style=\"font-size:18px;font-weight:bold;color:#ffffff;margin-bottom:6px;\">${SITE_NAME}</div>\n              <div style=\"font-size:13px;color:#94a3b8;margin-bottom:16px;\">Keeping you informed every week</div>\n              <div style=\"border-top:1px solid #334155;padding-top:16px;margin-top:8px;\">\n                <a href=\"${SITE_URL}\" style=\"color:#60a5fa;text-decoration:none;font-size:13px;margin:0 12px;\">Website</a>\n                <span style=\"color:#475569;\">\u2022</span>\n                <a href=\"${SITE_URL}/unsubscribe\" style=\"color:#60a5fa;text-decoration:none;font-size:13px;margin:0 12px;\">Unsubscribe</a>\n              </div>\n              <div style=\"font-size:11px;color:#64748b;margin-top:16px;\">\u00a9 ${new Date().getFullYear()} ${SITE_NAME}. All rights reserved.</div>\n            </td>\n          </tr>\n\n        </table>\n      </td></tr>\n    </table>\n  </center>\n</body>\n</html>`;\n\nreturn {\n  newsletter_html: newsletterHtml,\n  newsletter_date: newsletterData.newsletter_date,\n  article_count: Array.isArray(newsletterData.articles) ? newsletterData.articles.length : 0,\n  overview: newsletterData.overview || '',\n  articles: newsletterData.articles,\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "7c645b92-1b67-4f42-ad62-3a8f394caf63",
      "name": "Send Newsletter",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1184,
        -288
      ],
      "parameters": {
        "sendTo": "={{ $json.Email }}",
        "message": "={{ $('Format HTML Email').first().json.newsletter_html }}",
        "options": {
          "senderName": "YOUR COMPANY Newsletter",
          "appendAttribution": false
        },
        "subject": "=Weekly Digest \u2014 {{ $('Format HTML Email').first().json.newsletter_date }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "b40318c1-13f7-4684-984b-06ec9be18d7e",
      "name": "Get Subscribers",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        992,
        -288
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "Yes",
              "lookupColumn": "Active"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/18tsSavciwUeXpLIiSk71Csv8C_i3ydZIeIckvYQlUPc/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "18tsSavciwUeXpLIiSk71Csv8C_i3ydZIeIckvYQlUPc",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/18tsSavciwUeXpLIiSk71Csv8C_i3ydZIeIckvYQlUPc/edit?usp=drivesdk",
          "cachedResultName": "DEMO CRM"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "34ded0a7-416f-4fa7-90e5-40faf332f2bb",
  "connections": {
    "Process Posts": {
      "main": [
        [
          {
            "node": "AI \u2014 Generate Summaries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch WP Posts": {
      "main": [
        [
          {
            "node": "Process Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM \u2014 GPT-4o": {
      "ai_languageModel": [
        [
          {
            "node": "AI \u2014 Generate Summaries",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Get Subscribers": {
      "main": [
        [
          {
            "node": "Send Newsletter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Schedule": {
      "main": [
        [
          {
            "node": "Fetch WP Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format HTML Email": {
      "main": [
        [
          {
            "node": "Get Subscribers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI \u2014 Generate Summaries": {
      "main": [
        [
          {
            "node": "Format HTML Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}