Skip to content

🗞️ Newsletters - Automate the upload flow (use email tool's hosted URL) #4702

@bradystroud

Description

@bradystroud

Background

The newsletter upload flow is still painful for marketing (Penny) three years after it was first flagged. Picking up the thread from a stack of prior issues:

📺 Harry's demo video for Penny: https://youtu.be/lrgF3T7Y0Qs

📝 Full findings doc (in branch chore/pin-and-update-deps): _docs/NEWSLETTER_AUTOMATION_FINDINGS.md (will land in its own PR)

Adam's feedback on #712 already pointed at the right answer two years ago: "Now you would send it with MailChimp or Campaign Monitor or Sendgrid?" — yes, exactly that.

Current process

  1. Marketing edits an HTML template (hand-coded, <!-- EDIT HERE --> markers)
  2. Save as _YYYY_MM__Title__.html (rigid underscore convention)
  3. Upload into public/images/newsletter-uploads/<YYYY>/
  4. Run scripts/fix_newsletter_images.py (rewrites case-mismatched <img> paths)
  5. Run scripts/fix-newsletter-titles.py (needs Azure AI credentials to de-dupe <title> tags)
  6. Open Tina /admin → add row to content/newsletters/_<YYYY>.json (month, file path, description)
  7. Commit / PR / deploy
  8. Send the actual email via Dynamics 365 (Customer Insights – Journeys) — repo isn't even the source of truth for the sent email

Pain points

  • Brittle filename convention; easy to break
  • content/newsletters/_2025.json line 31 has %2520 (double-encoded space) from manual entry
  • Description drifts across three places (JSON / filename / <title>) — Mar 2025 says "Why Rules are Cool" in JSON but the filename says "…The Secret to Smarter Teams"
  • Two Python scripts a non-dev must run locally; one needs Azure AI credentials
  • No append helper — _2025.json has months in random order
  • HTML template authoring with <!-- EDIT HERE --> markers is itself a friction point upstream
  • Tina upload was supposed to fix this (✨Newsletters - File Upload on TinaCMS #821) but failed for Penny (🐛 Newsletter wont upload to Tina #1070); the issue was never closed

Why all this exists

We're hosting a second copy of an email that's already authored, stored, and hosted by Dynamics 365. Every major email tool — Dynamics 365 Customer Insights, Mailchimp, Campaign Monitor, HubSpot, Brevo — produces a permanent public "view in browser" URL per campaign. Storing that URL in Tina (instead of a hand-crafted HTML file) collapses steps 1–6 above.

Recommended path

Path 1 — Use the email tool's archive URL (smallest, fastest):

- file:        image upload   (HTML, requires fix-up scripts)
+ archiveUrl:  string         (paste the "view in browser" URL after sending)

NewslettersTable renders <a href={archiveUrl} target="_blank"> per row. Existing newsletters stay as static files in /newsletter-uploads/; schema accepts both file and archiveUrl during migration.

  • Cost: ~½ day dev work
  • Friction per newsletter after: ~5 seconds (paste one URL)
  • Blocker: confirm Dynamics produces a stable public archive URL per campaign

If marketing is open to migrating away from hand-coded HTML, Path 2 (move sending to Mailchimp's drag-and-drop editor, then Path 1) is the better long-term answer. Adam suggested this in 2023.

Cleanup to bundle into the same PR (whichever path)

Open questions for Adam / marketing

  1. Confirm the email tool is Dynamics 365 Customer Insights – Journeys.
  2. Does each Dynamics campaign produce a public "view as web page" URL we can link to?
  3. Any policy reason the newsletter HTML must live on ssw.com.au rather than the email tool's domain? (SEO: could mitigate with a redirect ssw.com.au/newsletters/2025/07 → archive URL.)
  4. Keep existing /images/newsletter-uploads/... URLs live forever? (Yes by default — archive integrity.)

cc @adamcogan @PennyWalker

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    🤷‍♂️ Needs Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions