7 Commits

Author SHA1 Message Date
will 6227d59eae Track altbody in change-detection so existing campaigns actually re-sync
CI / test (push) Successful in 10s
Campaign/parseCampaign never fetched altbody, so campaignUnchanged()
compared everything except it -- a campaign synced before v0.1.3
(altbody always null) whose content otherwise hasn't changed would be
judged unchanged forever and never get updated with the new altbody,
even though every subsequent sync now intends to send one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 22:13:13 -04:00
will e238bde036 Send altbody so campaigns actually go out multipart/alternative
CI / test (push) Successful in 9s
listmonk never derives a plaintext part from HTML/Markdown on its own
(models/campaigns.go only compiles AltBodyTpl, and
internal/manager/message.go only emits text/plain, when altbody is
explicitly non-null) -- confirmed against the deployed v6.2.0 source.
Every campaign this tool created was HTML-only as a result, contrary
to the README's now-corrected claim.

Reusing the same raw Markdown+template source as altbody personalizes
it identically to body, since AltBodyTpl compiles whenever the text
contains {{ }} expressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 22:05:49 -04:00
will 43c0604ac6 Always send messenger=email in campaign payloads
CI / test (push) Successful in 8s
Discovered while verifying the TestCampaign fix against real listmonk:
create/update apparently default an omitted messenger to "email"
server-side, but the test-send endpoint validates the raw request body
without that same defaulting, failing with "Unknown messenger .".
eec-campaigns only ever targets email, so send it explicitly instead
of depending on an inconsistency between endpoints.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 21:54:30 -04:00
will 39d02303c7 Fix TestCampaign sending only subscribers, failing listmonk validation
CI / test (push) Successful in 9s
listmonk's /api/campaigns/:id/test handler binds the request into the
same campReq struct create/update use and validates it in full, so a
request with only {"subscribers": [...]} fails with "Invalid length
for name" before subscribers is ever read. TestCampaign now sends the
campaign's full CampaignInput alongside subscribers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 21:51:20 -04:00
will a630a8f8ab Add template-as-code sync (campaigns template NAME PATH)
Answers "can the unsubscribe template be added via git+API too": commit
listmonk's own stock campaign template (already unsubscribe-capable) as
email-templates/campaign.html, add a small find-or-create-or-update
Template client (confirmed against knadh/listmonk's actual model/handlers),
a new `template` subcommand, and a manual-dispatch-only workflow to push it
in as the default campaign template. Unlike campaign sync there's no
draft/live status to protect, so this is always a safe overwrite.
2026-07-10 08:54:31 -04:00
will bcf8df5579 Fix campaign/listmonk API shapes against confirmed source, not guesses
Read knadh/listmonk's actual Go source (cmd/campaigns.go, cmd/subscribers.go)
instead of relying on incomplete public docs. Two corrections: the media
attach field is "media" (plain IDs), not "media_ids" as originally guessed;
and there's a single query-based bulk list action
(PUT /api/subscribers/query/lists) that applies a segment_query server-side,
so resolveSegment no longer fetches subscriber IDs client-side before
bulk-adding them. Create-status-defaults-to-draft and the test-send
"subscribers" field are now confirmed rather than flagged TODO(verify).
2026-07-10 08:37:07 -04:00
will b16d2b6c5f Initial implementation of the eec-campaigns tool
Drives listmonk's real Campaign API from git-authored Markdown+frontmatter,
so broadcast/segment emails get listmonk's mature unsubscribe/bulk-send/
attachment handling instead of reimplementing it. sync only ever creates or
updates a draft (idempotent, diff-based, refuses to touch a non-draft
campaign); a pushed send/<slug> tag or manual workflow run is the only way
to actually trigger a send. Includes list-name resolution, segment_query
materialization into managed lists, content-hash-deduped attachment
uploads, and an automatic post-sync preview email.
2026-07-10 07:30:45 -04:00