AutomationFlowsAI & RAG › Send Weekly Curated News Newsletters with Bright Data, Claude, and Gmail

Send Weekly Curated News Newsletters with Bright Data, Claude, and Gmail

ByToolMonsters @toolmonsters on n8n.io

This workflow runs every Monday to scrape Google News with Bright Data, fetch and clean the full text of the top five unique stories, generate an HTML newsletter with Anthropic Claude, and send it via Gmail. Runs every Monday on a scheduled trigger. Uses Bright Data to scrape a…

Cron / scheduled trigger★★★★☆ complexityAI-powered14 nodes@Brightdata/N8N Nodes BrightdataAnthropicGmail
AI & RAG Trigger: Cron / scheduled Nodes: 14 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #16675 — we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "",
  "name": "Automated News Newsletter powered by Bright Data",
  "tags": [],
  "nodes": [
    {
      "id": "5992efd8-9c4d-493a-94bd-a39f9887e2eb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -304
      ],
      "parameters": {
        "width": 480,
        "height": 864,
        "content": "## Automated News Newsletter powered by Bright Data\n\n### How it works\n\nThis workflow runs on a schedule to build an automated news newsletter. It uses Bright Data to scrape Google News, filters the results to the top five stories, then loops through each story to scrape and clean the full article content. After aggregating the cleaned articles, it asks Claude to write a newsletter and sends the final result via Gmail.\n\n### Setup steps\n\n- Configure the Schedule Trigger with the desired newsletter frequency.\n- Add Bright Data credentials and configure the Google News scrape target or query in the Bright Data nodes.\n- Add Anthropic credentials for the Claude newsletter-writing node and verify the prompt matches the desired newsletter style.\n- Connect Gmail credentials and configure the sender, recipient list, subject line, and email body mapping.\n\n### Customization\n\nAdjust the Google News query, the number of stories selected in the filter code, the article-cleaning logic, Claude's writing prompt, and the Gmail recipients or subject line to match the target audience."
      },
      "typeVersion": 1
    },
    {
      "id": "c02b0735-eed3-4cbb-8f24-362b1ae58feb",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 304,
        "content": "## Schedule and select stories\n\nStarts the workflow on a schedule, scrapes Google News with Bright Data, filters the result down to the top five stories, and initializes batch processing for each story."
      },
      "typeVersion": 1
    },
    {
      "id": "cb033b18-d636-4723-8e8f-c9f0c42a99ed",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 496,
        "content": "## Scrape article content\n\nFor each selected story, fetches the full article through Bright Data and normalizes the returned content into a clean format before sending control back to the story loop."
      },
      "typeVersion": 1
    },
    {
      "id": "d0a5c922-5f0c-4897-8533-2fbf08e8897e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        -304
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 336,
        "content": "## Generate newsletter draft\n\nCollects all cleaned article content after the loop completes and sends the aggregated material to Claude to write the newsletter."
      },
      "typeVersion": 1
    },
    {
      "id": "9af25b69-66fc-464d-8ced-2b6ce3a987b0",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 240,
        "height": 320,
        "content": "## Send final newsletter\n\nEmails the generated newsletter through Gmail to the configured recipients."
      },
      "typeVersion": 1
    },
    {
      "id": "c4270d50-be44-4f68-9b85-2435cca03fbc",
      "name": "When Week Starts",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ]
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1bf2bab6-b236-4a8c-85d0-399389413d6d",
      "name": "Extract Google News",
      "type": "@brightdata/n8n-nodes-brightdata.brightData",
      "position": [
        208,
        0
      ],
      "parameters": {
        "url": "https://www.google.com/search?q=AI+automation&tbm=nws&gl=us&hl=en&brd_json=1",
        "zone": {
          "__rl": true,
          "mode": "list",
          "value": "n8n_unlocker"
        },
        "country": {
          "__rl": true,
          "mode": "list",
          "value": "us"
        },
        "requestOptions": {}
      },
      "credentials": {
        "brightdataApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8567ccda-8df4-46d1-aa8f-12f7e64b5468",
      "name": "Select Top 5 News Stories",
      "type": "n8n-nodes-base.code",
      "position": [
        416,
        0
      ],
      "parameters": {
        "jsCode": "// Get the news array from the Bright Data node\nconst news = $input.first().json.news || [];\n\n// Filter out YouTube videos, keep only real news\nconst filtered = news.filter(item => {\n  const link = (item.link || \"\").toLowerCase();\n  const isVideo = link.includes(\"youtube.com\") || link.includes(\"youtu.be\");\n  return !isVideo && item.title && item.link;\n});\n\n// Dedupe by title\nconst seen = new Set();\nconst deduped = filtered.filter(item => {\n  if (seen.has(item.title)) return false;\n  seen.add(item.title);\n  return true;\n});\n\n// Keep top 5\nconst top5 = deduped.slice(0, 5);\n\n// Return each story as a separate item (for the loop ahead)\nreturn top5.map(item => ({ json: item }));"
      },
      "typeVersion": 2
    },
    {
      "id": "9f5c9a8b-15d1-4ab6-86fd-26a466743031",
      "name": "Loop Over News Stories",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        624,
        0
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "8f3cee52-99b4-4463-84a0-fdbc4454f741",
      "name": "Fetch Article Content",
      "type": "@brightdata/n8n-nodes-brightdata.brightData",
      "position": [
        928,
        240
      ],
      "parameters": {
        "url": "={{ $json.link }}",
        "zone": {
          "__rl": true,
          "mode": "list",
          "value": "n8n_unlocker"
        },
        "country": {
          "__rl": true,
          "mode": "list",
          "value": "us"
        },
        "data_format": "markdown",
        "requestOptions": {}
      },
      "credentials": {
        "brightdataApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4581608c-ac48-41e8-b696-b77607db0027",
      "name": "Sanitize Article Content",
      "type": "n8n-nodes-base.code",
      "position": [
        1152,
        400
      ],
      "parameters": {
        "jsCode": "// Web Unlocker may return [\"markdown...\"], a string, or an object\nlet raw = $input.first().json;\n\nlet content = \"\";\nif (Array.isArray(raw)) {\n  content = raw[0] || \"\";\n} else if (typeof raw === \"string\") {\n  content = raw;\n} else {\n  // Object: take the longest string found\n  for (const key in raw) {\n    if (typeof raw[key] === \"string\" && raw[key].length > content.length) {\n      content = raw[key];\n    }\n    // Sometimes it's raw.data[0] or similar\n    if (Array.isArray(raw[key]) && typeof raw[key][0] === \"string\") {\n      if (raw[key][0].length > content.length) content = raw[key][0];\n    }\n  }\n}\n\n// Try to drop everything before the real article start\n// Many sites put the title as \"# \" then the body \u2014 keep the last H1 section\nconst h1Split = content.split(/\\n# /);\nif (h1Split.length > 1) {\n  content = \"# \" + h1Split[h1Split.length - 1];\n}\n\n// Strip markdown links [text](url) \u2192 keep the text\ncontent = content.replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\");\n// Strip images ![...](...)\ncontent = content.replace(/!\\[[^\\]]*\\]\\([^)]*\\)/g, \"\");\n\n// Keep only real text lines (> 50 chars)\nlet lines = content.split(\"\\n\").map(l => l.trim()).filter(l => l.length > 50);\nlet cleaned = lines.join(\"\\n\\n\").slice(0, 2500);\n\nreturn [{\n  json: {\n    title: $('Loop Over News Stories').item.json.title,\n    link: $('Loop Over News Stories').item.json.link,\n    source: $('Loop Over News Stories').item.json.source,\n    content: cleaned\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "5cf7d631-ed3c-4e4a-81af-d183c8f0d13e",
      "name": "Compile All Articles",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1136,
        -128
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "f0fec1de-3d66-4e3f-94b7-a9c112abfe38",
      "name": "Compose Newsletter with Claude",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        1328,
        -128
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "claude-opus-4-8",
          "cachedResultName": "claude-opus-4-8"
        },
        "options": {
          "system": "=You are a newsletter editor. You write concise, engaging newsletters from industry news articles.\n\nFor each article you receive, write:\n- A bold headline (use the article title)\n- Two or three sentences summarizing the key points IN YOUR OWN WORDS, based on the article content provided\n- A \"Read more\" link using the article's link\n\nFormat the whole thing as clean HTML ready to drop into an email: <h2> for the newsletter title at the top, <h3> for each headline, <p> for summaries, <a> for the links. Start with a short one-sentence intro before the first story.\n\nOutput ONLY the HTML. No markdown code fences, no preamble, no explanation."
        },
        "messages": {
          "values": [
            {
              "content": "=Here are today's top 5 industry news articles. Write the newsletter.\n\n{{ JSON.stringify($json.data.map(a => ({ title: a.title, link: a.link, source: a.source, content: a.content }))) }}"
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "120f68c8-9057-4481-a77f-5d205405a585",
      "name": "Email Newsletter via Gmail",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1680,
        -16
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "={{ $json.content[0].text }}",
        "options": {},
        "subject": "Your AI Industry Brief"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "",
  "nodeGroups": [],
  "connections": {
    "When Week Starts": {
      "main": [
        [
          {
            "node": "Extract Google News",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Google News": {
      "main": [
        [
          {
            "node": "Select Top 5 News Stories",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compile All Articles": {
      "main": [
        [
          {
            "node": "Compose Newsletter with Claude",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Article Content": {
      "main": [
        [
          {
            "node": "Sanitize Article Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over News Stories": {
      "main": [
        [
          {
            "node": "Compile All Articles",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fetch Article Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sanitize Article Content": {
      "main": [
        [
          {
            "node": "Loop Over News Stories",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Top 5 News Stories": {
      "main": [
        [
          {
            "node": "Loop Over News Stories",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compose Newsletter with Claude": {
      "main": [
        [
          {
            "node": "Email Newsletter via Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow runs every Monday to scrape Google News with Bright Data, fetch and clean the full text of the top five unique stories, generate an HTML newsletter with Anthropic Claude, and send it via Gmail. Runs every Monday on a scheduled trigger. Uses Bright Data to scrape a…

Source: https://n8n.io/workflows/16675/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Complaints arrive via Gmail or a web form webhook Claude AI classifies each complaint: fault category, priority (P1/P2/P3), tenant tone, and drafts an acknowledgement email The right technician is loo

Anthropic, Airtable, Gmail +2
AI & RAG

This workflow runs daily and checks Google Shopping prices for product keywords stored in Google Sheets using Bright Data snapshots, then uses Anthropic Claude to exclude accessories and identify the

Google Sheets, @Brightdata/N8N Nodes Brightdata, Anthropic
AI & RAG

A schedule trigger periodically fetches the list of URLs to monitor from your CRM (Airtable by default) Bright Data Web Unlocker scrapes each page (handles JS, CAPTCHAs, geo-blocks) Claude Sonnet 4.6

Airtable, @Brightdata/N8N Nodes Brightdata, Anthropic +1
AI & RAG

This workflow is a complete outbound automation system that discovers local businesses, extracts contact emails, generates personalized cold emails using AI, and runs a multi-step follow-up sequence —

Stop And Error, Google Sheets, HTTP Request +2
AI & RAG

Personalized Outreach & Follow-Up - Phase 2. Uses googleSheets, openAi, gmail, gmailTrigger. Scheduled trigger; 59 nodes.

Google Sheets, OpenAI, Gmail +2