Newsletter Workflow: BookStack to Listmonk (Draft Automation)

Newsletter Workflow: BookStack → Listmonk (draft automation)

What we're automating

Publishing a newsletter is a two-app chore: the content lives in the Chronicle book of BookStack (book id 24), and the send happens in Listmonk. Right now each issue is moved by hand. This page records the process we followed for the September 2026 issue and the plan to automate the "draft it into Listmonk" half of it in n8n.

Why drafts — not scheduled sends

When a campaign is created in Listmonk with no send_at date, it is stored as a draft and stays there until a human schedules or sends it. That is exactly the right automation boundary:

The manual process (what the September 2026 issue looked like)

  1. Locate the issue in the Chronicle: book id 24, chapter "2026", page "September 2026 Newsletter" (page id 220 on 2026-09-07).
  2. Read the page's raw content. BookStack's WYSIWYG editor stores it as markdown with <span data-preserver-spaces="true"> wrappers around nearly every block and inline run.
  3. Strip the span tags to recover clean markdown, then convert to the richtext HTML Listmonk wants. Verification: check for balanced **/*, no leftover <tags>, links intact, heading levels preserved.
  4. Create the campaign via the Listmonk MCP server with:
    • name = page name ("September 2026 Newsletter")
    • subject = a punchy topic phrase, matching the house style (e.g. "What's Really in Your Teacup? Part II: Beyond Organic")
    • lists = [3] (Newsletter Welcome)
    • template_id = 1 (Default campaign template)
    • content_type = "richtext", body = the converted HTML
    • tags = a consistent scheme (safe set: newsletter, a topic tag, a date tag such as september-2026)
  5. Confirm status is draft, with the full body intact via get_campaign.

Note on finished campaigns: Listmonk refuses to update campaigns whose status is finished or running ("Cannot update a running or a finished campaign"). So tags and content must be set while the campaign is a draft. Once something has gone out you can no longer edit it — tag at creation.

MCP routes and clients used

All use the same Authorization: Basic <base64> header from ~/.hermes/config.yaml (the mcphub entry). Two front-ends exist; verify with tools/list first because they shift:

The plan: automate the drafting in n8n

Goal: when a new page is created in the Chronicle, n8n drafts it into Listmonk. The flow (built from the n8n MCP server's capabilities):

  1. Trigger — BookStack webhook on page_create → n8n Webhook node. (Fallback if webhooks aren't wired: Schedule + HTTP polling of /api/pages, de-duped.)
  2. Filter — If node: only proceed when book_id == 24 (Chronicle).
  3. Fetch — HTTP GET https://bookstack.tea-tavern.com/api/pages/{id} with Authorization: Token <bookstack-api-token>.
  4. Convert — Code node: strip the data-preserver-spaces spans, then markdown→HTML to the richtext body Listmonk expects.
  5. Draft — HTTP POST https://listmonk.tea-tavern.com/api/campaigns with Authorization: Token <listmonk-api-token> and the campaign body above, no send_at, so it's created as a draft.

Credentials needed in n8n's store: a BookStack API token and a Listmonk API token. Open decisions: how the subject line is derived (the page name is "September 2026 Newsletter", not the punchy subject), and whether tags should be read from the page's BookStack tags instead of hard-coded.

Tag scheme (house convention)


Revision #1
Created 2026-09-07 05:08:55 UTC by MCP Server
Updated 2026-09-07 05:08:55 UTC by MCP Server