-
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathgreat-docs.yml
More file actions
207 lines (187 loc) · 9.23 KB
/
Copy pathgreat-docs.yml
File metadata and controls
207 lines (187 loc) · 9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# Great Docs Configuration
# See https://posit-dev.github.io/great-docs/user-guide/configuration.html
# Friendly name shown in the navbar / page titles.
display_name: Listmonk
# Docstring style is Google ("Args:" / "Returns:" sections). Pin it; don't rely on
# auto-detect (init detected google=38).
parser: google
# Dynamic introspection imports the package at build time for accurate signatures.
# Requires great-docs to run in a venv where `import listmonk` succeeds.
dynamic: true
# Subpath hosting: drives Quarto's base path so CSS/JS/nav resolve under /docs/listmonk/.
# Keep the trailing slash.
site_url: "https://mkennedy.codes/docs/listmonk/"
# GOTCHA G7: sitemap/robots/canonical/og:url use a SEPARATE base URL that Great Docs
# auto-detects from the GitHub repo (-> owner.github.io/repo) and does NOT fall back to
# site_url. Set it explicitly, or the sitemap points at the wrong domain.
seo:
canonical:
base_url: "https://mkennedy.codes/docs/listmonk/"
# Source repository + "view source" links and install/version badges.
repo: https://github.com/mikeckennedy/listmonk
github_style: widget
source:
enabled: true
branch: main
placement: usage
pypi: true
# GOTCHA G5: Great Docs defaults mcp.enabled to TRUE, rendering an empty "MCP" tab even
# with no MCP server. Disable it — this project ships no MCP server.
mcp:
enabled: false
# Umami analytics — merged into Quarto's format.html.include-in-header, so it lands in
# the <head> of every generated page.
include_in_header:
- text: |
<script async src="https://uma.mkennedy.codes/script.js" data-website-id="fc9b6770-3b44-4073-944e-4a4f0e79f66a"></script>
# Agent skill enrichment. The generated skill already carries the API signatures;
# this block adds the sharp edges and wiring the signatures can't convey.
skill:
# Hand-written prose injected into the generated skill body: end-to-end wiring, the
# raises-vs-returns-False error model, the mutate-then-pass-back update pattern, Go
# template syntax, and media/attachment flows. Adapted from the listmonk_reference.md
# agent guide.
extra_body: skill_extra_body.md
gotchas:
- "Call set_url_base() then login() before any other function, or every data call raises OperationNotAllowedError."
- "login(), is_healthy(), and verify_login() return False (they do not raise) when credentials are rejected or the server is unreachable — check the bool."
- "Timeouts use httpx2 (a fork of httpx), not httpx: build them with httpx2.Timeout(...) and catch httpx2.HTTPStatusError."
- "Every template body must contain the Go-template placeholder {{ template \"content\" . }} exactly once, or create_template() raises ValueError. It is Go template syntax, not Jinja."
- "update_campaign() replaces the whole attachment set: media_ids=None re-sends the campaign's existing media, media_ids=[] clears them, and a new list swaps them. A past send_at is silently dropped to None."
- "update_campaign() cannot change a campaign's status — Listmonk ignores `status` on PUT /api/campaigns/{id}. Use set_campaign_status() (or start/pause/cancel_campaign()), which calls the dedicated /status endpoint."
- "test_campaign() only delivers to addresses that already exist as subscribers; Listmonk will not create them, and a test to an unknown address silently sends nothing."
- "subscribers(query_text=...) requires the subscribers:sql_query permission on the user's role, or the server returns HTTP 403."
- "send_transactional_email() requires the recipient to already be a subscriber, and template_id must reference a 'tx' template, not a 'campaign' template."
- "Auth is module-level global state: only one instance can be targeted at a time and credential changes are not thread-safe."
- "Custom email headers are a list of single-entry dicts (e.g. [{'X-Priority': '1'}]), not one dict."
best_practices:
- "Configure set_url_base() then login() once at startup and check login()'s bool return before proceeding."
- "Update objects by fetching the model, mutating fields in place, then passing it back to update_subscriber/update_campaign/update_template — the client re-fetches and returns the server's fresh copy."
- "Use block_subscriber() to unsubscribe someone while keeping their record; use delete_subscriber() to erase them entirely."
- "Attach files to a campaign with upload_media() then media_ids=[...]; attach to a transactional email inline via attachments=[Path(...)]."
- "Preview a campaign with campaign_preview_by_id(), then test_campaign(id, ['you@example.com']) to a real inbox, before start_campaign() sends it to the lists."
- "Pass the models.CampaignStatuses enum to set_campaign_status() rather than a raw string — an unrecognized status reaches Postgres and comes back as an opaque HTTP 500."
- "Pass a custom httpx2.Timeout via timeout_config for slow or self-hosted instances (the default is 10 seconds)."
decision_table:
- need: "Look up a single subscriber"
use: "subscriber_by_email(email) / subscriber_by_id(id) / subscriber_by_uuid(uuid)"
- need: "Filter subscribers by a custom attribute"
use: "subscribers(query_text=\"subscribers.attribs->>'city' = 'Portland'\")"
- need: "Unsubscribe someone but keep their record"
use: "block_subscriber(subscriber)"
- need: "Erase a subscriber entirely"
use: "delete_subscriber(email)"
- need: "Send a one-off email (reset code, receipt)"
use: "send_transactional_email(email, tx_template_id, template_data={...})"
- need: "Attach a file to a campaign"
use: "upload_media(path) then create_campaign(..., media_ids=[m.id])"
- need: "Schedule a campaign for later"
use: "create_campaign(..., send_at=datetime.now() + timedelta(hours=1))"
- need: "Send a test copy of a campaign to yourself"
use: "test_campaign(campaign_id, ['you@example.com'])"
- need: "Actually send a draft campaign"
use: "start_campaign(campaign_id) — or set_campaign_status(id, CampaignStatuses.running)"
- need: "Stop a campaign that is sending"
use: "pause_campaign(campaign_id) to resume later, cancel_campaign(campaign_id) to stop for good"
# Author metadata for the landing-page sidebar.
authors:
- name: Michael Kennedy
role: Author
email: michael@talkpython.fm
# Jupyter kernel for any executable code cells in generated pages.
jupyter: python3
# API Reference Structure
# -----------------------
# Grouped by task. listmonk is a flat module: top-level functions are bare names
# (resolve to listmonk.<name>); models live under models.<Name>; exceptions under
# errors.<Name>.
reference:
title: "API Reference"
desc: "The full listmonk client API: configuration, list/subscriber/campaign/template management, and transactional email."
sections:
- title: Configuration & Authentication
desc: "Point the client at your Listmonk instance and authenticate."
contents:
- set_url_base
- get_base_url
- login
- verify_login
- is_healthy
- title: Mailing Lists
desc: "Read and manage mailing lists."
contents:
- lists
- list_by_id
- create_list
- update_list
- delete_list
- title: Subscribers
desc: "Create, query, update, and manage the status of subscribers."
contents:
- subscribers
- subscriber_by_email
- subscriber_by_id
- subscriber_by_uuid
- create_subscriber
- update_subscriber
- add_subscribers_to_lists
- enable_subscriber
- disable_subscriber
- block_subscriber
- confirm_optin
- delete_subscriber
- title: Campaigns
desc: "Create, preview, update, test, send, and delete email campaigns."
contents:
- campaigns
- campaign_by_id
- campaign_preview_by_id
- create_campaign
- update_campaign
- test_campaign
- set_campaign_status
- start_campaign
- pause_campaign
- cancel_campaign
- delete_campaign
- title: Media
desc: "Upload files to the media library to attach to campaigns."
contents:
- upload_media
- title: Templates
desc: "Manage email templates and set the default."
contents:
- templates
- template_by_id
- template_preview_by_id
- create_template
- update_template
- set_default_template
- delete_template
- title: Transactional Email
desc: "Send one-off transactional messages."
contents:
- send_transactional_email
- title: Data Models
desc: "Pydantic models returned by and passed to the API functions."
contents:
- models.MailingList
- models.SubscriberStatus
- models.SubscriberStatuses
- models.Subscriber
- models.CreateSubscriberModel
- models.Campaign
- models.CampaignStatuses
- models.CreateCampaignModel
- models.UpdateCampaignModel
- models.CampaignPreview
- models.Template
- models.CreateTemplateModel
- models.TemplatePreview
- models.Media
- title: Exceptions
desc: "Errors raised by the client."
contents:
- errors.ValidationError
- errors.OperationNotAllowedError
- errors.ListmonkFileNotFoundError