diff --git a/README.md b/README.md index a1a4f3a..81f34cd 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,11 @@ attachments: --- Campaign body goes here, in Markdown. It's sent to listmonk with -content_type "markdown" — listmonk renders the HTML *and* derives the -plaintext alternative itself. +content_type "markdown" for the HTML part; listmonk never derives a +plaintext alternative on its own, so this same source is also sent +verbatim as `altbody` — recipients on plaintext-only clients see the +raw Markdown (and personalization still resolves, since the `{{ }}` +expressions are still there), rather than getting an HTML-only email. ``` - **`subject`** — required. diff --git a/internal/listmonk/listmonk.go b/internal/listmonk/listmonk.go index 8387a14..9dae237 100644 --- a/internal/listmonk/listmonk.go +++ b/internal/listmonk/listmonk.go @@ -335,7 +335,17 @@ func (in CampaignInput) payload() map[string]any { "lists": in.ListIDs, "content_type": "markdown", "body": in.Body, - "type": in.Type, + // listmonk never derives a plaintext alternative from body/HTML on its + // own (models/campaigns.go only compiles AltBodyTpl, and + // internal/manager/message.go only emits a text/plain part, when + // altbody is explicitly non-null) — confirmed against the deployed + // v6.2.0 source. Reusing the same raw Markdown+template source as the + // altbody gets it personalized identically to body (AltBodyTpl compiles + // whenever the text contains {{ }} expressions), at the cost of + // Markdown syntax like *emphasis* showing up literally in plaintext + // clients — an acceptable, well-established tradeoff for Markdown. + "altbody": in.Body, + "type": in.Type, // listmonk's create/update handlers default an omitted messenger to // "email" before validating, but the test-send handler validates the // raw request body as-is — an omitted messenger there fails with