Automatic newsletter generator and RSS/Atom aggregator built on Google Apps Script. It fetches configured feeds, normalizes items into a Google Sheet, and renders a daily HTML newsletter (email + optional web preview).
- Feed ingestion:
Feed.gsfetches and parses feeds listed inConfig.gs. New items are normalized and written to sheet tabs defined byConfig. - Mailer:
AutoMailer.gsbuilds visible sections (usingbuildVisibleSectionsForDate), rendersNewsletter_Mail.html, and sends the daily email viasendDailyNewsletter(). - Web preview:
doGet(e)inAutoMailer.gs/ web handlers rendersNewsletter_Web.htmlfor a requested date. Deploy as a Web App to expose a permalink.
Key properties (set in Project Settings β Script properties):
| Property | Description | Required / Notes |
|---|---|---|
SHEET_ID |
ID of the Google Sheet that stores feed tabs and feed data | Required |
ANALYTICS_SPREADSHEET_ID |
(Deprecated) Spreadsheet ID where analytics events are logged (Analytics_Events, Analytics_Daily). Prefer ANALYTICS_ENDPOINT. |
Optional - deprecated |
ANALYTICS_ENDPOINT |
URL of an analytics endpoint that accepts POST /track JSON events (recommended). Example: a deployed newsletter-analytics-service |
Recommended (for robust tracking) |
ANALYTICS_LOG_USER |
When set to true, the webapp will attach the server-side active user's email (Session.getActiveUser().getEmail()) to events sent to ANALYTICS_ENDPOINT. Use with care (PII). |
Optional (default: false) |
ANALYTICS_SECRET |
Some secret string (base64) to perform very basic HMAC | Recommended (for tracking) |
ANALYTICS_SEND_MAPPINGS |
When set to true, the mailer will POST incremental rid->email mappings to the analytics backend during sends. |
Optional (default: false) |
ANALYTICS_SEND_PLAIN_EMAIL |
When set to true, the mailer will POST incremental rid->email mappings in plaintext to the analytics backend during sends. |
Optional (default: false) |
SEND_TO |
Comma-separated list of recipient emails for the newsletter | Required unless TEST_RECIPIENT is set |
TEST_RECIPIENT |
Sends newsletter only to this address (overrides SEND_TO), useful for testing |
Optional (use for safe testing) |
WEBAPP_URL |
Deployed Web App URL used for the web preview and analytics POST fallback |
Optional (set to enable web preview links) |
MAX_ITEMS_PER_SECTION |
How many items to show in each section in the email preview (default: 6) | Optional (default: 6) |
If WEBAPP_URL is set, outgoing emails include a "View full newsletter" link that points to the web preview.
- Open the project in the Apps Script editor.
- Deploy β New deployment β choose "Web app".
- Set "Execute as" to
Me. Choose access according to whether you want public view (Anyone) or authenticated access. - Copy the returned URL and set it to
WEBAPP_URLin Script properties.
Once deployed, recipients can open WEBAPP_URL?date=YYYY-MM-DD to view a full newsletter page.
This project includes lightweight analytics for clicks, page views and active time:
WebAnalytics.gsexposes adoPost(e)JSON API that acceptslogEventandlogActiveTimeactions and forwards them tologEventApi/logActiveTimeApi.SharedAnalytics.gsprovidessendAnalyticsEvent()which POSTs a normalized JSON payload toANALYTICS_ENDPOINTwhen configured. This is the recommended way to collect analytics. IfANALYTICS_ENDPOINTis not set the function logs an error and is a no-op.
More details on the backend service can be found in newsletter-analytics-service/.
Warning
The mail analytics and sheet analytics are not fully implemented due to limitations with email clients and GAS. The mail analytics code is present in MailAnalytics.gs but do not work reliably.
Note
Prefer setting ANALYTICS_ENDPOINT to an HTTP(S) endpoint that accepts POST /track JSON events (the repo includes a sample service in newsletter-analytics-service/).
If you still rely on spreadsheet-based analytics, ANALYTICS_SPREADSHEET_ID is still supported but deprecated β the codebase now prefers POSTing events to ANALYTICS_ENDPOINT.
Caution
If you enable ANALYTICS_LOG_USER=true, the webapp will attempt to attach the server-side active user's email address to analytics events. This exposes personally-identifiable information (PII) to your analytics backend and may have legal/privacy implications depending on your jurisdiction and policy. Only enable if you have consent and a clear retention policy.
- Templates:
Newsletter_Mail.htmlandNewsletter_Web.htmluse Apps Script scriptlets (<?= ... ?>) β edit in the Apps Script editor or viaclasp. - Web endpoints:
WebAnalytics.gshandles web GET/POST (pixel, redirects, pings) and routes JSON POSTs tologEventApi/logActiveTimeApi. - Analytics helpers:
SharedAnalytics.gs(event row format, HMAC helpers),SheetsAnalytics.gs(sheet-side helpers), andMailAnalytics.gs(mailer link signing) live undersrc/Analytics/. - If you add scopes (Sheets API, UrlFetch, etc.), update
appsscript.jsonand re-authorize.
Local / clasp
Note
Node.js is required to run any of the follwoing commands.
-
Clone this repo:
git clone https://github.com/joejo-joestar/OilGas-Wire.git cd OilGas-Wire/newsletter-scripts -
Run these commands:
npm i
clasp login
clasp pull
clasp push
-
Open the project in the Apps Script editor.
- Set Script properties (
SHEET_ID,ANALYTICS_SPREADSHEET_ID,WEBAPP_URL, etc.). - Populate the feed config sheet (tab named
Feed_Config) with feed URLs and target sheet tabs. - In
Utils/Debug.gs, run thetestRun()function to fetch feeds and populate the sheet. - Deploy the web app and visit
WEBAPP_URL?preview=1to preview the full HTML. - Run
sendDailyNewsletterto test sending (useTEST_RECIPIENTduring tests).
- Open the web preview and click headlines. The page will attempt to POST tracking payloads (check the browser Network panel).
- Confirm
Analytics_Events(sheet) orAnalytics_Debug(if enabled) receives rows.
- In Apps Script editor: Triggers β Add Trigger β choose
sendDailyNewsletterβ Time-driven β Day timer β set hour.
OilGas-Wire/
βββ README.md
βββ assets/
βββ newsletter-analytics-service/ # The GCP service for analytics
β βββ Dockerfile
β βββ package.json
β βββ index.js
β βββ newsletter_analytics.*.json # BigQuery schema files
β βββ newsletter_analytics.*.sql # BigQuery create table queries
β βββ README.md
βββ newsletter-scripts/ # The main Apps Script project
βββ appsscript.json
βββ package.json
βββ AutoMailer.gs
βββ Config.gs
βββ Feed.gs
βββ IDFScoreGen.gs
βββ Newsletter_Mail.html
βββ Newsletter_Web.html
βββ Styles_Common.html
βββ Styles_Email.html
βββ Styles_Web.html
βββ Triggers.gs
βββ Web_Preview.html
βββ Analytics/ # Analytics-related scripts
β βββ MailAnalytics.gs
β βββ SheetsAnalytics.gs
β βββ SharedAnalytics.gs
β βββ WebAnalytics.gs
βββ Utils/
βββ Analysis.gs
βββ Debug.gs
βββ FeedUtils.gs
βββ SheetUtils.gs
βββ TextUtils.gs
βββ UnitTests.gs
- Aggregates RSS/Atom feeds and writes normalized rows to Google Sheets.
- Generates a daily HTML newsletter (email + web app) with configurable sections.
- Web app includes client-side tracking (page views, headline clicks, active time) that writes to an analytics spreadsheet.
- A lightweight preview UI (
WebPreview.html) served by the web app for manual QA. Visit the webapp with?preview=1to open a date picker and preview rendered HTML for any date.
- Uses TF-IDF scoring to identify and sort by relevant articles (see
IDFScoreGen.gs).





