Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

You can automate a daily newsletter by scheduling a Playwright job to collect pages from an approved source list, normalize and deduplicate the findings, generate an HTML and plain-text draft, and validate it before sending through an email provider. Keep collection, editorial review, and delivery as separate steps: browser automation can gather material, but it cannot decide what deserves publication or guarantee that an email is lawful or deliverable.

Design the workflow before automating it

Start with a small, explicit list of sources and a definition of what belongs in the issue. A reliable pipeline should leave enough information to trace every newsletter item back to its original page, and it should make failures visible rather than silently publishing a partial issue.

  1. Schedule and identify the run. Choose a fixed timezone and create a unique run ID, such as the scheduled date plus a short identifier. Record the start time, completion time, and outcome.
  2. Collect from allowlisted URLs. Use Playwright to open only sources you have selected. Prefer a site’s feed or public API when it supplies the material you need; use browser automation when the relevant content is available only in the rendered page. Check site terms and access rules, and do not try to defeat a login, paywall, CAPTCHA, or other access control.
  3. Save evidence before transforming it. Retain the raw HTML and capture metadata such as the requested URL, final URL, page title, collection time, and any publication timestamp found. This makes it possible to inspect an extraction error without relying on the transformed newsletter item.
  4. Normalize and deduplicate. Compare canonical URLs, titles, and publication times. Keep the original page URL with each item, even when you use a canonical URL for matching.
  5. Apply editorial rules. Define source-quality thresholds, a recency window, topic tags, and rules for excluding duplicates or low-value pages. Put ambiguous items in a human-review queue rather than treating a successful page load as approval to publish.
  6. Render and validate the issue. Generate HTML and plain text. Check titles, links, image alternative text, source attribution, sender details, and the unsubscribe footer before delivery.
  7. Send and monitor separately. Use an email provider to send the approved issue and retain delivery, bounce, complaint, and unsubscribe events. A browser script that creates a draft is not a substitute for those delivery controls.

Set up Playwright for collection

Playwright is documented as a cross-browser automation API for Chromium, Firefox, and WebKit; its BrowserType API can launch a browser or connect to an existing browser instance. Microsoft also documents Playwright automation for Microsoft Edge. For a scheduled collector, start with one browser engine and an isolated context for each run so cookies and storage from one run do not accidentally affect another. Use a persistent profile only if a source legitimately requires a session and you are authorized to use it.

The example below uses Node.js and Chromium. It expects a sources.json file containing source URLs and page-specific selectors. It saves each successful page’s HTML and metadata, extracts configured links, removes duplicate candidates, and writes an HTML and plain-text draft. It deliberately does not send email: review the output and connect a provider only after adding its authentication, unsubscribe, and event-handling requirements.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

1. Install the browser automation package

In a new project directory, install Playwright and its Chromium browser:

npm init -y
npm install playwright
npx playwright install chromium

2. Define a source allowlist

Create sources.json. Choose selectors that match the pages you actually intend to collect; the selectors below are examples, not universal selectors for every site.

[
  {
    "url": "https://example.com/news",
    "itemSelector": "article a",
    "titleSelector": "h1",
    "publishedSelector": "time[datetime]"
  }
]

3. Run the collector

Save this as newsletter.js and run it with node newsletter.js. It rejects URLs whose hostname is not in the configured allowlist, applies timeouts, records per-source errors, and writes drafts even when an individual source fails. Review the generated files and the errors array before publishing.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
const { chromium } = require('playwright');
const fs = require('node:fs/promises');
const path = require('node:path');
const crypto = require('node:crypto');

const runId = new Date().toISOString().replace(/[:.]/g, '-');
const outputDir = path.join('runs', runId);
const sources = JSON.parse(await fs.readFile('sources.json', 'utf8'));
const allowedHosts = new Set(sources.map(s => new URL(s.url).hostname));
const items = [];
const errors = [];

await fs.mkdir(path.join(outputDir, 'pages'), { recursive: true });
const browser = await chromium.launch({ headless: true });

try {
  const context = await browser.newContext();
  for (const source of sources) {
    let page;
    try {
      const requested = new URL(source.url);
      if (!['http:', 'https:'].includes(requested.protocol) ||
          !allowedHosts.has(requested.hostname)) {
        throw new Error('URL is outside the configured HTTP(S) allowlist');
      }

      page = await context.newPage();
      page.setDefaultTimeout(10000);
      const response = await page.goto(source.url, {
        waitUntil: 'domcontentloaded', timeout: 20000
      });
      if (!response || !response.ok()) {
        throw new Error(`Page response: ${response ? response.status() : 'none'}`);
      }

      const finalUrl = page.url();
      if (!allowedHosts.has(new URL(finalUrl).hostname)) {
        throw new Error('Redirected outside the configured hostname allowlist');
      }
      const html = await page.content();
      const pageTitle = await page.title();
      const canonical = await page.locator('link[rel="canonical"]')
        .getAttribute('href').catch(() => null);
      const publication = source.publishedSelector
        ? await page.locator(source.publishedSelector).first()
            .getAttribute('datetime').catch(() => null)
        : null;

      const filename = crypto.createHash('sha256')
        .update(source.url).digest('hex').slice(0, 16);
      await fs.writeFile(path.join(outputDir, 'pages', `${filename}.html`), html);
      await fs.writeFile(path.join(outputDir, 'pages', `${filename}.json`),
        JSON.stringify({ runId, collectedAt: new Date().toISOString(),
          requestedUrl: source.url, finalUrl, pageTitle, canonical, publication,
          status: response.status() }, null, 2));

      const links = await page.locator(source.itemSelector).evaluateAll(els =>
        els.map(el => ({ title: (el.innerText || el.textContent || '').trim(),
          href: el.href || el.getAttribute('href') || '' })));
      for (const link of links) {
        if (!link.title || !link.href) continue;
        const url = new URL(link.href, finalUrl);
        if (!['http:', 'https:'].includes(url.protocol) ||
            !allowedHosts.has(url.hostname)) continue;
        url.hash = '';
        const normalizedUrl = url.toString();
        items.push({ title: link.title.replace(/s+/g, ' '),
          url: normalizedUrl, sourceUrl: source.url,
          sourceTitle: pageTitle, publishedAt: publication });
      }
    } catch (error) {
      errors.push({ source: source.url, message: String(error.message || error) });
    } finally {
      if (page) await page.close().catch(() => {});
    }
  }
  await context.close();
} finally {
  await browser.close();
}

const seen = new Set();
const unique = items.filter(item => {
  const key = item.url.toLowerCase();
  if (seen.has(key)) return false;
  seen.add(key);
  return true;
});
const escapeHtml = s => s.replace(/[&<>"']/g, c =>
  ({ '&':'&amp;', '<':'&lt;', '>':'&gt;',
     '"':'&quot;', "'":'&#39;' }[c]));
const html = `<!doctype html><html><body>
<h1>Daily newsletter draft</h1><ul>${unique.map(i =>
  `<li><a href="${escapeHtml(i.url)}">${escapeHtml(i.title)}</a>
  <small>Source: <a href="${escapeHtml(i.sourceUrl)}">${escapeHtml(i.sourceTitle)}</a></small></li>`).join('')}
</ul><p>Sources are linked with each item.</p></body></html>`;
const plain = ['Daily newsletter draft', '', ...unique.flatMap(i =>
  [i.title, i.url, `Source: ${i.sourceUrl}`, ''])].join('n');
await fs.writeFile(path.join(outputDir, 'draft.html'), html);
await fs.writeFile(path.join(outputDir, 'draft.txt'), plain);
await fs.writeFile(path.join(outputDir, 'run.json'), JSON.stringify({
  runId, finishedAt: new Date().toISOString(),
  collectedItems: items.length, uniqueItems: unique.length, errors
}, null, 2));
console.log(`Draft: ${outputDir}; ${unique.length} unique items; ${errors.length} source errors`);

Before relying on the draft generator, inspect whether source-specific links point to actual stories or merely navigation, whether the site’s canonical URL represents the same content, and whether dates are publication dates rather than update dates. The example deduplicates by normalized URL; for feeds with frequent URL variants, also compare normalized titles and publication timestamps, but preserve the original URLs in the review data.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Schedule the run and make failures observable

Use a scheduler with an explicit timezone rather than relying on a machine’s unstated local setting. On a Linux host using cron, for example, set the host timezone deliberately and schedule a command that writes standard output and errors to a log. This example runs at 07:00 server-local time every day; it is not a timezone-independent cron expression.

0 7 * * * cd /path/to/newsletter-job && /usr/bin/node newsletter.js >> /var/log/newsletter-job.log 2>&1

If daylight-saving changes matter, use a scheduler that accepts an IANA timezone such as America/New_York, and confirm its behavior for skipped or repeated local times. Record a run ID and keep the run manifest, page snapshots, and error log long enough to diagnose a missed issue. Alert on failed runs, an unexpectedly empty result set, an unusually high error count, or a draft that was generated without passing review. Add bounded retries for transient network errors, with a limit and backoff; repeated retries should not turn a blocked source into an endless job.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Review the issue before sending it

Automated collection should create candidates, not publish unreviewed claims. A practical review queue can show the item title, destination URL, source URL, publication time, source-quality status, duplicate match, and a checkbox for inclusion. Set a recency window that fits the newsletter’s cadence, and mark items with missing or questionable timestamps for review rather than assuming they are new.

  • Confirm that every included item has a meaningful title and a working, expected destination.
  • Retain a sources section or source link for every item, and check that the text accurately reflects the linked page.
  • Check image alternative text if images are included; do not treat a screenshot or decorative image as a substitute for accessible text.
  • Generate and read both the HTML and plain-text versions, including the footer and all links.
  • Send a dry run to an internal recipient list before the first scheduled issue and after material template or collection changes.
  • Keep the editorial decision and run records distinct from the email provider’s delivery, bounce, complaint, and unsubscribe records.

Meet email and endorsement requirements

For commercial email covered by U.S. CAN-SPAM rules, the FTC says messages need truthful routing information, a non-deceptive subject, a valid physical postal address, and a clear opt-out method. The FTC says opt-outs must be honored within 10 business days, and that the opt-out mechanism must remain usable for at least 30 days after the message is sent. Those figures are U.S. federal guidance; requirements elsewhere may differ, and this is not legal advice. Build the opt-out path into the delivery provider and verify that unsubscribed recipients are excluded from later sends.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If a newsletter recommends a product in exchange for a commission or another benefit, disclose the relationship clearly and conspicuously near that recommendation. FTC endorsement guidance cautions that simply saying “affiliate link” may not explain the relationship clearly enough. Do not bury the disclosure in a general footer when the reader needs it to understand a specific recommendation.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If the useful result is a clean visual record of a page rather than extracted article text, a screenshot API can be a separate step in the workflow. ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Its API accepts one GET request for a URL and returns a PNG, JPEG, WebP, or PDF. A screenshot is a visual artifact; it does not replace extracting, checking, and sourcing newsletter claims.

ScreenshotNeo API documentation

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers indicate the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. See ScreenshotNeo for the service details.

Sign up free for 1,000 screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot common failures

A source times out or returns an error

Check whether the site is reachable from the scheduled host, whether it redirects to a different hostname, and whether the configured timeout is appropriate. Log status and final URL, retry only transient failures a limited number of times, and move persistent failures into the review queue. Do not bypass a site’s access controls.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

The job succeeds but extracts no items

The page may have changed its markup, rendered content after the initial navigation event, or use a selector that matches no article links. Inspect the saved HTML and adjust the source-specific selector. If content appears only after a particular element is present, wait for that selector with a bounded timeout rather than adding an unbounded sleep.

The draft contains navigation links or duplicates

Narrow the selector to story links and compare canonical URLs, normalized titles, and publication timestamps. Keep the original URL for attribution even if a normalized URL is used as the deduplication key. Have a person resolve collisions where two distinct stories share similar titles.

The scheduled run does not happen at the expected local time

Verify the scheduler host’s timezone, daylight-saving behavior, executable path, working directory, and log permissions. A cron schedule follows the host’s configured time behavior; use a timezone-aware scheduler if the send must occur at a particular local time throughout the year.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The issue is sent to someone who unsubscribed or has a broken opt-out

Do not treat the browser job as the subscription database. Use the email provider’s suppression and unsubscribe handling, test the opt-out flow, and review event records before the next send. Pause delivery until the suppression issue is corrected.

Performance, reliability, and operating cost

Browser sessions cost more time and resources than fetching a small feed or API response, so use the lightest authorized source that supplies the needed data. Keep source concurrency conservative: an isolated context does not make high-volume requests appropriate. Reuse a browser process within a run if useful, but create fresh pages and close them in a finally path. Bound navigation and selector waits, cap retries, and record partial completion so one unavailable source does not conceal which other sources were collected.

Operating cost depends on where the browser runs, the number and complexity of pages, storage and logging retention, and the email provider’s plan; the available facts here do not establish a universal price or runtime. Measure your own scheduled workload and provider charges. Track the count of pages attempted, successful captures, extracted candidates, unique items, review exclusions, delivery outcomes, and unsubscribes. These are operational signals, not a guarantee of newsletter quality or inbox placement.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.