LogicLoop Logo
LogicLoop
LogicLoop / devops-practices / 7 Steps to Build an Automated Newsletter Workflow with Puppeteer and OpenRouter
devops-practices May 14, 2025 8 min read

7 Essential Steps to Build a Fully Automated Newsletter Workflow System for Content Creators

Priya Narayan

Priya Narayan

Systems Architect

7 Steps to Build an Automated Newsletter Workflow with Puppeteer and OpenRouter

Creating and maintaining a weekly newsletter can be time-consuming, especially when you need to collect, organize, and summarize content from various sources. By implementing an automated newsletter workflow, you can streamline this process and focus on curating quality content instead of handling repetitive tasks. This guide walks through building a comprehensive newsletter automation system that collects blog posts throughout the week and generates a polished newsletter every Wednesday morning.

Understanding the Newsletter Automation Challenge

A typical newsletter workflow involves several tedious steps: bookmarking interesting articles, reading and summarizing them, organizing the content into sections, and formatting everything into a cohesive newsletter. For content creators and curators, these repetitive tasks consume valuable time that could be better spent on content strategy and audience engagement.

Our automation solution addresses these pain points by creating a system that handles the collection, storage, and processing of content with minimal manual intervention. The workflow consists of two main components: a web hook that captures and processes content as you discover it, and a scheduled task that compiles everything into a newsletter.

The Architecture of an Automated Newsletter System

Before diving into implementation details, let's outline the high-level architecture of our newsletter automation system:

  1. A web hook endpoint that receives URLs when new content is bookmarked
  2. A web crawler (using Puppeteer) that processes the URL and extracts content
  3. A storage mechanism to save processed content to Google Drive
  4. A scheduled job that runs weekly to compile saved content
  5. An integration with OpenRouter to generate the final newsletter
  6. Metadata handling to maintain source attribution and organization
  7. Delivery mechanism to send the newsletter to subscribers

This architecture allows for a seamless flow from content discovery to newsletter delivery, with automation handling the heavy lifting at each stage.

Implementation of the newsletter automation API endpoint showing webhook configuration for content processing and storage
Implementation of the newsletter automation API endpoint showing webhook configuration for content processing and storage

Step 1: Setting Up the Content Collection Webhook

The first component of our newsletter workflow automation is a webhook that captures URLs when you bookmark content. This endpoint will receive the URL, process it, and store the content for later use in your newsletter.

JAVASCRIPT
// API endpoint to receive URLs for processing
app.post('/api/submit-url', async (req, res) => {
  try {
    const { url, author } = req.body;
    
    if (!url) {
      return res.status(400).json({ error: 'URL is required' });
    }
    
    // Process the URL using Puppeteer
    const content = await crawlWebsite(url, author);
    
    // Save the content to Google Drive
    await saveToGoogleDrive(content, url);
    
    res.status(200).json({ message: 'URL processed successfully' });
  } catch (error) {
    console.error('Error processing URL:', error);
    res.status(500).json({ error: 'Failed to process URL' });
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

This endpoint can be integrated with bookmarking tools like Raindrop.io, which can be configured to call your webhook whenever you save a new bookmark. This creates a seamless workflow where content is automatically processed as you discover it throughout the week.

Step 2: Implementing the Web Crawler with Puppeteer

Puppeteer is a Node.js library that provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It's perfect for our newsletter automation workflow because it allows us to render JavaScript-heavy pages and extract their content just as a user would see it.

JAVASCRIPT
async function crawlWebsite(url, author) {
  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  try {
    const page = await browser.newPage();
    await page.goto(url, { waitUntil: 'networkidle2' });
    
    // Extract content from the page
    const htmlContent = await page.content();
    
    // Convert HTML to markdown for easier processing
    const turndownService = new TurndownService();
    let markdownContent = turndownService.turndown(htmlContent);
    
    // Process and convert images to base64
    markdownContent = await processImages(page, markdownContent);
    
    // Add metadata
    const metadata = {
      url: url,
      author: author || await extractAuthor(page),
      date: new Date().toISOString(),
      title: await page.title()
    };
    
    return {
      content: markdownContent,
      metadata: metadata
    };
  } finally {
    await browser.close();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Code implementation showing TurndownService for converting HTML to markdown and image handling functionality that converts external images to base64 format
Code implementation showing TurndownService for converting HTML to markdown and image handling functionality that converts external images to base64 format

The crawler converts HTML content to markdown format, which is easier to work with for text processing. It also handles images by converting them to base64 format, ensuring they're preserved within the content without requiring external references.

Step 3: Storing Processed Content in Google Drive

Once the content is processed, we need to store it for later use. Google Drive provides a convenient storage solution that's accessible from anywhere and integrates well with other tools.

JAVASCRIPT
async function saveToGoogleDrive(content, originalUrl) {
  // Authenticate with Google Drive API
  const auth = new google.auth.GoogleAuth({
    keyFile: 'credentials.json',
    scopes: ['https://www.googleapis.com/auth/drive']
  });
  
  const drive = google.drive({ version: 'v3', auth });
  
  // Get the current week's folder or create it
  const folderName = getWeekFolderName();
  const folderId = await getOrCreateFolder(drive, folderName);
  
  // Create a file name based on the content title
  const fileName = `${content.metadata.title.substring(0, 50).replace(/[^a-z0-9]/gi, '-')}.md`;
  
  // Prepare the file content
  const fileContent = `---
title: ${content.metadata.title}
url: ${originalUrl}
author: ${content.metadata.author}
date: ${content.metadata.date}
---

${content.content}`;
  
  // Upload the file to Google Drive
  await drive.files.create({
    requestBody: {
      name: fileName,
      parents: [folderId],
      mimeType: 'text/markdown'
    },
    media: {
      mimeType: 'text/markdown',
      body: fileContent
    }
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

This function organizes content into weekly folders, making it easy to gather all relevant content when it's time to generate the newsletter. The content is stored in markdown format with metadata at the top, preserving all the information needed for attribution and organization.

Step 4: Scheduling the Newsletter Generation

The next step in our newsletter workflow automation is to schedule the generation of the newsletter. We'll use Cloudflare Workers or a similar serverless platform to run a scheduled task that compiles the content and generates the newsletter.

JAVASCRIPT
// Schedule the newsletter generation every Tuesday afternoon
app.get('/api/generate-newsletter', async (req, res) => {
  try {
    // Get the current week's folder
    const folderName = getWeekFolderName();
    const folderId = await getFolderId(drive, folderName);
    
    if (!folderId) {
      return res.status(404).json({ error: 'No content found for this week' });
    }
    
    // Retrieve all files from the folder
    const files = await getFilesInFolder(drive, folderId);
    
    // Compile the content from all files
    const compiledContent = await compileContent(drive, files);
    
    // Generate the newsletter using OpenRouter
    const newsletter = await generateNewsletter(compiledContent);
    
    // Save the newsletter to Google Drive
    await saveNewsletter(drive, newsletter, folderName);
    
    res.status(200).json({ message: 'Newsletter generated successfully' });
  } catch (error) {
    console.error('Error generating newsletter:', error);
    res.status(500).json({ error: 'Failed to generate newsletter' });
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Newsletter automation implementation showing scheduled Tuesday generation with error handling and content compilation functionality
Newsletter automation implementation showing scheduled Tuesday generation with error handling and content compilation functionality

This endpoint can be triggered by a scheduled task set up in Cloudflare Workers or a similar platform. The task retrieves all content saved during the week, compiles it, and passes it to the next step for newsletter generation.

Step 5: Generating the Newsletter with OpenRouter

OpenRouter is a platform that provides access to various language models. We'll use it to generate our newsletter by providing the compiled content and a system prompt that defines the tone and structure of the newsletter.

JAVASCRIPT
async function generateNewsletter(compiledContent) {
  // Prepare the system prompt
  const systemPrompt = `
    You are an expert newsletter writer creating a weekly newsletter about technology.
    Your tone is informative, engaging, and slightly conversational.
    Structure the newsletter with:
    1. A compelling introduction
    2. Summaries of the most important articles
    3. Thematic grouping of related content
    4. A brief conclusion
    
    Include proper attribution for all content.
  `;
  
  // Call OpenRouter API
  const response = await axios.post('https://openrouter.ai/api/v1/chat/completions', {
    model: 'openai/gpt-4',
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: `Generate a newsletter based on the following content: ${JSON.stringify(compiledContent)}` }
    ]
  }, {
    headers: {
      'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  });
  
  return response.data.choices[0].message.content;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

The system prompt is crucial for guiding the language model to generate a newsletter with the right tone and structure. You can customize this prompt to match your newsletter's style and focus. OpenRouter allows you to choose from different language models, so you can select the one that best fits your needs and budget.

Step 6: Finalizing and Distributing the Newsletter

The final step in our newsletter workflow automation is to save the generated newsletter and prepare it for distribution to subscribers. This could involve sending it via email, publishing it on a website, or both.

JAVASCRIPT
async function saveNewsletter(drive, newsletter, weekFolder) {
  // Create a formatted date for the newsletter title
  const date = new Date();
  const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
  
  // Save the newsletter to Google Drive
  await drive.files.create({
    requestBody: {
      name: `Newsletter-${formattedDate}.md`,
      parents: [weekFolder],
      mimeType: 'text/markdown'
    },
    media: {
      mimeType: 'text/markdown',
      body: newsletter
    }
  });
  
  // You could add code here to send the newsletter via email
  // or publish it to a website
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

This function saves the generated newsletter to Google Drive in the same folder as the source content. You could extend this to include email distribution using services like SendGrid or Mailchimp, or to publish the newsletter to a website or platform like Substack.

Benefits of Automating Your Newsletter Workflow

  • Time savings: Reduce manual work by automating content collection and processing
  • Consistency: Ensure your newsletter maintains a consistent structure and tone
  • Scalability: Easily handle more content sources without increasing workload
  • Flexibility: Modify your workflow as needed without rebuilding from scratch
  • Focus: Spend more time on content curation and strategy rather than mechanics

Customizing Your Newsletter Automation System

The system described above provides a solid foundation for newsletter workflow automation, but there are many ways to customize it to better fit your specific needs:

  • Content filtering: Add logic to filter or categorize content based on keywords or topics
  • Multiple sources: Extend the system to collect content from RSS feeds, social media, or other sources
  • Advanced formatting: Implement custom formatting rules for different types of content
  • Analytics integration: Track open rates, click-through rates, and other metrics to optimize your newsletter
  • Personalization: Generate personalized newsletters for different segments of your audience

By automating the mechanical aspects of newsletter creation, you free up time and mental energy to focus on what truly matters: finding and sharing valuable content with your audience. The system described in this article provides a solid foundation that you can build upon and customize to create a newsletter workflow that perfectly fits your needs.

Conclusion

Creating an automated newsletter workflow may require some initial setup, but the long-term benefits far outweigh the investment. By automating content collection, processing, and newsletter generation, you can create a more consistent, scalable, and efficient process that allows you to focus on content curation rather than mechanical tasks.

The combination of Puppeteer for web crawling, Google Drive for storage, and OpenRouter for content generation provides a powerful and flexible system that can be adapted to various newsletter formats and requirements. As AI technologies continue to evolve, the possibilities for further automation and enhancement will only grow.

Let's Watch!

7 Steps to Build an Automated Newsletter Workflow with Puppeteer and OpenRouter

Ready to enhance your neural network?

Access our quantum knowledge cores and upgrade your programming abilities.

Initialize Training Sequence
L
LogicLoop

High-quality programming content and resources for developers of all skill levels. Our platform offers comprehensive tutorials, practical code examples, and interactive learning paths designed to help you master modern development concepts.

© 2025 LogicLoop. All rights reserved.