{"result":{"depiction_url":null,"edges":{"in_module":{"objects":[{"created":"2026-09-29T13:07:54Z","object_id":{"id":1465,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_mailinglist","title":"mod_mailinglist","uri":"https:\/\/zotonic.com\/id\/1465"},"seq":1}],"predicate":{"id":333,"is_a":["meta","predicate"],"name":"in_module","title":{"_type":"trans","tr":{"en":"In module"}},"uri":"https:\/\/zotonic.com\/id\/in_module"}},"subject":{"objects":[{"created":"2026-09-29T13:07:54Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-09-29T13:07:54Z","object_id":{"id":2564,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_backend_developer","title":"Backend developer","uri":"https:\/\/zotonic.com\/id\/2564"},"seq":2},{"created":"2026-09-29T13:07:54Z","object_id":{"id":2597,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_mailing_lists","title":"Mailing lists","uri":"https:\/\/zotonic.com\/id\/2597"},"seq":3},{"created":"2026-09-29T13:07:54Z","object_id":{"id":2625,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_model","title":"Model","uri":"https:\/\/zotonic.com\/id\/2625"},"seq":4},{"created":"2026-09-29T13:07:54Z","object_id":{"id":2654,"is_a":["categorization","keyword","keyword_task"],"name":"zotonic_topic_send_and_receive","title":"Send and receive","uri":"https:\/\/zotonic.com\/id\/2654"},"seq":5},{"created":"2026-09-29T13:07:54Z","object_id":{"id":2656,"is_a":["categorization","keyword","keyword_task"],"name":"zotonic_topic_schedule","title":"Schedule","uri":"https:\/\/zotonic.com\/id\/2656"},"seq":6},{"created":"2026-09-29T13:07:54Z","object_id":{"id":2657,"is_a":["categorization","keyword","keyword_task"],"name":"zotonic_topic_monitor","title":"Monitor","uri":"https:\/\/zotonic.com\/id\/2657"},"seq":7}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":2711,"is_a":["text","documentation","reference","model"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/2711"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_model_model_mailinglist_run","page_url":{"en":"https:\/\/zotonic.com\/docs\/2711\/mailinglist_run","x-default":"https:\/\/zotonic.com\/docs\/2711\/mailinglist_run"},"preview_url":null,"resource":{"version":19,"pivot_location_lat":null,"title":"mailinglist_run","is_authoritative":true,"body":"<p>Durable mailing runs and delivery accounting, available as <code>m.mailinglist_run<\/code> in templates.\nRecipient addresses and message diagnostics are never published on MQTT.\nInternal worker functions require an already authorized sender context.<\/p>\n<h2>Available Model API Paths<\/h2>\n<table class=\"table\"><thead><tr><th>Method<\/th><th>Path pattern<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>get<\/code><\/td><td><code>\/<\/code><\/td><td>List accessible runs, optionally filtered by a payload map.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/history\/...<\/code><\/td><td>Return accessible runs and a next-page offset, using the same payload filters as the root path.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/run\/+run_id\/...<\/code><\/td><td>Return a run with aggregate statistics, language results and saved-content metadata.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/recipients\/+run_id\/...<\/code><\/td><td>Return up to 100 recipient results, optionally filtered and paged using the payload.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/page\/+page_id\/...<\/code><\/td><td>List accessible runs for a page. Resource names and ids are accepted.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/list\/+list_id\/...<\/code><\/td><td>List accessible runs for a mailinglist. Resource names and ids are accepted.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/history_expired\/+page_id\/+list_id\/...<\/code><\/td><td>Return whether any run for this page\/list pair has expired recipient details. Both ids must be numeric.<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>\/recent\/...<\/code><\/td><td>Return up to five accessible recent runs, newest first, from the latest 200 runs.<\/td><\/tr><\/tbody><\/table>\n<p><code>\/+name<\/code> marks a variable path segment. A trailing <code>\/...<\/code> means extra path segments\nare returned for further lookups. Run ids accept integers or numeric binaries.\nUnrecognized paths return <code>{error, unknown_path}<\/code>.<\/p>\n<h2>Run lists and filters<\/h2>\n<p>List results contain run metadata, including ids, language settings, status, timestamps,\ntest\/resend information, errors and <code>details_expired<\/code>, plus a <code>stats<\/code> map.\nExcept for <code>\/recent<\/code>, runs in <code>preparing<\/code>, <code>sending<\/code>, <code>retrying<\/code> or <code>interrupted<\/code> status\ncome first; within each group the newest creation time and id come first.\nEach query selects at most 200 rows before checking access, so fewer rows may be returned.<\/p>\n<p>The root path accepts a payload map with binary keys:<\/p>\n<table class=\"table\"><thead><tr><th>Key<\/th><th>Default<\/th><th>Meaning<\/th><\/tr><\/thead><tbody><tr><td><code>status<\/code><\/td><td>Empty binary<\/td><td>Exact run status; empty means all statuses.<\/td><\/tr><tr><td><code>language<\/code><\/td><td>Empty binary<\/td><td>Exact run language setting; empty means all languages.<\/td><\/tr><tr><td><code>page_id<\/code><\/td><td><code>0<\/code><\/td><td>Numeric page id; zero means all pages.<\/td><\/tr><tr><td><code>list_id<\/code><\/td><td><code>0<\/code><\/td><td>Numeric mailinglist id; zero means all lists.<\/td><\/tr><tr><td><code>offset<\/code><\/td><td><code>0<\/code><\/td><td>Rows to skip before access checks, capped at 1,000,000.<\/td><\/tr><\/tbody><\/table>\n<p>For example, <code>m.mailinglist_run::%{status: &quot;scheduled&quot;, list_id: id}<\/code> lists scheduled\nruns for a mailinglist. <code>m.mailinglist_run.page[id]<\/code> lists runs for a page.\nFilters apply to the root and <code>\/history<\/code> paths; <code>\/page<\/code>, <code>\/list<\/code> and <code>\/recent<\/code> ignore the payload.\n<code>\/history<\/code> returns a map with <code>runs<\/code> and <code>next_offset<\/code>. Use <code>next_offset<\/code> as the next\nrequest&#39;s <code>offset<\/code>; <code>undefined<\/code> means there is no next page (or the offset cap was reached).\nPagination is based on database rows, independently of access filtering. A page may\ncontain fewer than 200 visible runs, or none, while still providing a next-page offset.<\/p>\n<h2>Run details and statistics<\/h2>\n<p><code>m.mailinglist_run.run[run_id]<\/code> returns the run without its internal <code>pickled_context<\/code>,\n<code>options<\/code>, <code>props<\/code> or <code>request_key<\/code>. It adds:<\/p>\n<ul><li><code>stats<\/code>: recipient counts per status, plus <code>total<\/code>, <code>selected<\/code>, <code>waiting<\/code>,\n<code>unsuccessful<\/code>, <code>processed<\/code> and integer <code>percent<\/code>.<\/li><li><code>languages<\/code>: nonzero counts as maps containing <code>language<\/code>, <code>status<\/code> and <code>total<\/code>,\nordered by language and status.<\/li><li><code>copies<\/code>: saved-content metadata containing <code>language<\/code> and <code>created<\/code>, ordered by language.<\/li><li><code>first_submitted<\/code>: the first email submission timestamp, if available.<\/li><li><code>test_address<\/code>: the single test recipient address, if this run has one.<\/li><li><code>language_policy<\/code>: <code>all<\/code> to use the fallback for unavailable preferences, or\n<code>matching<\/code> to skip unavailable or unset preferences when choosing languages\nautomatically. Absent on older runs, which keep their original behavior.<\/li><\/ul>\n<p><code>selected<\/code> excludes skipped recipients; <code>waiting<\/code> sums pending, submitting, queued and\nretrying recipients. <code>unsuccessful<\/code> sums failed and bounced recipients. <code>processed<\/code> is\nselected minus waiting; <code>percent<\/code> is the integer percentage processed, or zero if none\nwere selected. Individual status keys with no recorded count may be absent.\nSent counts mean acceptance by the receiving mail server, not confirmed inbox delivery.\nSaved HTML is read through <code>content\/3<\/code> and the saved-content controller, not an <code>m_get<\/code> path.<\/p>\n<h2>Recipient results<\/h2>\n<p>The <code>\/recipients\/+run_id<\/code> payload accepts <code>status<\/code> and <code>after<\/code> with binary keys.\n<code>status<\/code> can be <code>pending<\/code>, <code>submitting<\/code>, <code>queued<\/code>, <code>retrying<\/code>, <code>sent<\/code>, <code>failed<\/code>,\n<code>bounced<\/code>, <code>skipped<\/code> or <code>cancelled<\/code>. An omitted, empty or unrecognized status means all.\n<code>after<\/code> is a recipient-row id, defaulting to zero. Results are ordered by id ascending;\nuse the last returned id as <code>after<\/code> to fetch the next batch of up to 100 rows.<\/p>\n<p>Each result contains <code>id<\/code>, <code>email<\/code>, <code>language<\/code>, <code>status<\/code>, <code>reason<\/code> and <code>modified<\/code>.\nFor example: <code>m.mailinglist_run.recipients[run_id]::%{status: &quot;failed&quot;, after: last_id}<\/code>.\nExpired recipient details return an empty list; aggregate statistics remain available.<\/p>\n<h2>Access and expired history<\/h2>\n<p>Run reads require permission to use <code>mod_mailinglist<\/code>, visibility of the mailed page,\nand permission to edit the mailinglist. An authenticated sender may also read their own\ntest-list runs without edit permission on the test list. List paths omit inaccessible\nruns; <code>\/run<\/code> and <code>\/recipients<\/code> return <code>{error, eacces}<\/code> for missing or inaccessible runs.<\/p>\n<p><code>\/history_expired\/+page_id\/+list_id<\/code> instead checks\n<code>mod_mailinglist:is_allowed_to_send(ListId, PageId, Context)<\/code> and returns\n<code>{error, eacces}<\/code> if sending is not allowed. A true result means that recipient history\nfor this pair is incomplete, so a new mailing cannot reliably select only new or failed\nrecipients. It does not mean that every run for the pair has expired.<\/p>\n<p>Successful <code>m_get\/3<\/code> calls return <code>{ok, {Value, Rest}}<\/code>; templates receive <code>Value<\/code>\nand use any remaining path segments for further lookups.<\/p>","slug":"mailinglist_run","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"321ceed5d7125a181662e573acf52bd77b91803930023c52af66a8ef5ffccccd","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":322,"is_a":["meta","category"],"name":"model","title":"Models","uri":"https:\/\/test.zotonic.com\/id\/322"},"doc_source_path":"apps\/zotonic_mod_mailinglist\/src\/models\/m_mailinglist_run.erl","publication_start":"2026-09-29T13:07:54Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/apps\/zotonic_mod_mailinglist\/src\/models\/m_mailinglist_run.erl","pivot_location_lng":null,"doc_source_kind":"model","name":"doc_model_model_mailinglist_run","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2026-09-29T13:07:54Z","uri":null,"doc_status":"current","is_dependent":false,"erlang_app":"zotonic_mod_mailinglist","publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"85498256abd162b9bc082d43a90c995844fd4408\n","erlang_module":"m_mailinglist_run","creator_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"modified":"2026-09-29T14:40:25Z","title_slug":"mailinglist_run"},"uri":"https:\/\/zotonic.com\/id\/2711","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/2711"}},"status":"ok"}