DEV Community

Grewup
Grewup

Posted on

Build an AI Newsletter Agent That Reads the Web Every Morning (n8n + OpenRouter + Gemini)

What this builds

An automated AI newsletter agent that runs every night at midnight, searches the web for the most relevant news in your chosen niche, formats it into a professional HTML newsletter, emails it to you automatically, and logs every story to Google Sheets to prevent duplicates in future runs.

You wake up to fresh, relevant, personalised industry news. No manual research. No subscriptions to dozens of sources. No duplicate stories.

Architecture

Schedule Trigger (midnight daily)
        ↓
AI Agent (OpenRouter — GPT-4 via OpenRouter)
  Tools attached:
  ├── Google Gemini (live web search — past week)
  └── Think tool (internal quality check)
  Output: structured JSON with subject + 3 news items
        ↓
Gmail — send formatted HTML newsletter
        ↓
Code node — unbundle 3 items into individual rows
        ↓
Google Sheets — log each story (duplicate prevention)
Enter fullscreen mode Exit fullscreen mode

## Step 1 — Schedule Trigger

Add a Schedule Trigger node. Set it to fire at midnight daily.

Trigger interval: Days
Days between:     1
Hour:             0 (midnight)
Minute:           0
Enter fullscreen mode Exit fullscreen mode

## Step 2 — AI Agent node

Add an AI Agent node. Rename it News Research Agent.
Connect OpenRouter Chat Model. Toggle "Require Specific Output Format" to ON.

User prompt:

Send me the newsletter for today.
Enter fullscreen mode Exit fullscreen mode

System prompt:

You are an expert newsletter curator specializing in AI tool launches 
and industry developments. Your mission is to research the internet 
and create a daily newsletter summarizing the 3 most impactful AI 
tool launches or developments from the past week.

ROLE: AI Industry Newsletter Curator
OUTPUT COUNT: Exactly 3 news items
CHARACTER LIMIT: 150 words per news item maximum

**GUIDELINES:**
- Focus on NEW tool launches, significant updates, or industry-changing developments
- Prioritize tools that solve real business problems
- Include why each development matters to professionals
- Verify information from multiple sources when possible
- Maintain an engaging, professional tone

STRUCTURE: Provide your response in the following JSON format:
{
  "subject_line": "AI Weekly: [Key Theme] - [Date]",
  "news_items": [
    {
      "title": "Tool/Development Name",
      "content": "Brief description and key features",
      "why_it_matters": "Impact explanation for professionals",
      "source": "Primary source URL",
      "category": "Tool Launch/Update/Industry News"
    }
  ]
}

TOOLS AVAILABLE: You have access to internet search, thinking 
capabilities, and a Google Sheets log to avoid duplicate content.

AVOID:
- Outdated news (older than 1 week)
- Overly technical jargon without explanation
- Duplicate content from previous newsletters
- Speculation or unverified rumors
Enter fullscreen mode Exit fullscreen mode

Step 3 — Add the Gemini search tool

Click the Tools tab inside the AI Agent node. Add Google Gemini as a tool.

Model:          gemini-1.5-flash
Search recency: Past week
Enter fullscreen mode Exit fullscreen mode

Step 4 — Add the Think tool

Click Tools again. Add the Think tool. Paste this description:

Use the tool to think about something. It will not obtain new information 
or change the database, but just append the thought to the log. Use it 
when complex reasoning or some cache memory is needed.
Enter fullscreen mode Exit fullscreen mode

Step 5 — Structured Output Parser

Configure with this JSON schema:

{
  "subject_line": "AI Weekly Update - March 15, 2024",
  "news_items": [
    {
      "title": "Revolutionary AI Tool Launch",
      "content": "Description of the tool and its capabilities.",
      "why_it_matters": "Impact on industry professionals.",
      "source": "https://example.com",
      "category": "Tool Launch"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Select Google Gemini Chat Model as the model for the parser. Model: gemini-1.5-flash.

Step 6 — Gmail node

Operation:  Send Message
To:         your@email.com
Subject:    {{ $json.output.subject_line }}
Email type: HTML
Enter fullscreen mode Exit fullscreen mode

Message body (Expression mode):

<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
  <h1 style="color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px;">
    {{ $json.output.subject_line }}
  </h1>

  {{ $json.output.news_items.map(item => `
  <div style="margin: 25px 0; padding: 20px; background: #f8f9fa; border-radius: 8px; border-left: 4px solid #3498db;">
    <h2 style="color: #2c3e50; margin-top: 0;">${item.title}</h2>
    <span style="background: #3498db; color: white; padding: 3px 10px; border-radius: 12px; font-size: 12px;">${item.category}</span>
    <p style="color: #444; line-height: 1.6; margin-top: 12px;">${item.content}</p>
    <div style="background: #e8f4fd; padding: 12px; border-radius: 6px; margin-top: 12px;">
      <strong style="color: #2980b9;">Why it matters:</strong>
      <p style="color: #444; margin: 5px 0 0 0;">${item.why_it_matters}</p>
    </div>
    <a href="${item.source}" style="color: #3498db; text-decoration: none; font-size: 13px;">Read source →</a>
  </div>
  `).join('') }}

  <p style="color: #888; font-size: 12px; text-align: center; margin-top: 30px;">
    Generated by your AI newsletter agent · {{ new Date().toLocaleDateString() }}
  </p>
</div>
Enter fullscreen mode Exit fullscreen mode

Step 7 — Code node (unbundle)

const items = [];

const data = $('News Research Agent').first().json.output;
const subjectLine = data.subject_line || '';
const newsList = data.news_items || [];

for (const news of newsList) {
  items.push({
    json: {
      subject_line: subjectLine,
      title: news.title || '',
      content: news.content || '',
      source: news.source || '',
      category: news.category || '',
      date_logged: new Date().toISOString().split('T')[0]
    }
  });
}

return items;
Enter fullscreen mode Exit fullscreen mode

Step 8 — Google Sheets logging

Operation:  Append Row
Columns:
  subject_line: {{ $json.subject_line }}
  title:        {{ $json.title }}
  content:      {{ $json.content }}
  source:       {{ $json.source }}
  category:     {{ $json.category }}
  date_logged:  {{ $json.date_logged }}
Enter fullscreen mode Exit fullscreen mode

What breaks

Agent fabricates news instead of searching: Gemini tool is not connected. Check the Tools tab — Gemini should show a green connection indicator.

Structured Output Parser fails: Add this to your system prompt: "Return ONLY valid JSON. No markdown, no backticks, no explanation before or after the JSON object."

Code node throws undefined error: The node name in $('News Research Agent') does not match your actual node name. Case sensitive, space sensitive.

Gmail subject shows raw expression: Switch from Fixed to Expression mode in the subject field.

Workflow JSON available at elevoras.com. Import into n8n, connect your credentials, and activate.

What niche are you building this for? Drop it in the comments.

Top comments (0)