{"id":16105191,"url":"https://github.com/mikeckennedy/listmonk","last_synced_at":"2026-06-04T00:01:02.380Z","repository":{"id":218240328,"uuid":"745118465","full_name":"mikeckennedy/listmonk","owner":"mikeckennedy","description":"Listmonk Email App API Client for Python #pypackage","archived":false,"fork":false,"pushed_at":"2026-06-03T20:14:28.000Z","size":210,"stargazers_count":59,"open_issues_count":1,"forks_count":12,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-06-03T22:08:12.749Z","etag":null,"topics":["email","listmonk","listmonk-api","newsletter","newsletter-management","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikeckennedy.png","metadata":{"files":{"readme":"README.md","changelog":"change-log.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["mikeckennedy"]}},"created_at":"2024-01-18T17:16:52.000Z","updated_at":"2026-06-03T20:14:33.000Z","dependencies_parsed_at":"2024-01-20T17:32:19.669Z","dependency_job_id":"63bdd690-5b74-4faa-afa2-2499e6357a01","html_url":"https://github.com/mikeckennedy/listmonk","commit_stats":{"total_commits":65,"total_committers":3,"mean_commits":"21.666666666666668","dds":"0.19999999999999996","last_synced_commit":"702a7e91a2d29adb798564a4077ff754a7b630ff"},"previous_names":["mikeckennedy/listmonk"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/mikeckennedy/listmonk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Flistmonk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Flistmonk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Flistmonk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Flistmonk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikeckennedy","download_url":"https://codeload.github.com/mikeckennedy/listmonk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Flistmonk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33884734,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["email","listmonk","listmonk-api","newsletter","newsletter-management","python"],"created_at":"2024-10-09T19:08:46.872Z","updated_at":"2026-06-04T00:01:02.372Z","avatar_url":"https://github.com/mikeckennedy.png","language":"Python","funding_links":["https://github.com/sponsors/mikeckennedy"],"categories":["Python"],"sub_categories":[],"readme":"# Listmonk Email API Client for Python\n\nClient for the for open source, self-hosted [Listmonk email platform](https://listmonk.app) based on\n[httpx2](https://github.com/pydantic/httpx2) and [pydantic](https://pydantic.dev).\n\n`listmonk` is intended for integrating your Listmonk instance into your web app. The [Listmonk API is extensive](https://listmonk.app/docs/apis/apis/) but this only covers the subset that most developers will need for common SaaS actions such as subscribe, unsubscribe, and segmentate users (into separate lists).\n\nSo while it doesn't currently cover every endpoint (for example you cannot create a list programatically nor can you edit HTML templates for campaigns over APIs) it will likely work for you. That said, PRs are weclome.\n\n🔀 Async is currently planned but not yet implemented. With the httpx2-base, it should be trivial if needed.\n\n## Core Features\n\n- ➕**Add a subscriber** to your subscribed users.\n- 🙎 Get **subscriber details** by email, ID, UUID, and more.\n- 📝 **Modify subscriber details** (including custom attribute collection).\n- 🔍 **Search** your users based on app and custom attributes.\n- 🏥 Check the **health and connectivity** of your instance.\n- 👥 Retrieve your **segmentation lists**, list details, and subscribers.\n- 🙅 Unsubscribe and block users who don't want to be contacted further.\n- 💥 Completely delete a subscriber from your instance.\n- 📧 Send transactional email with template data (e.g. password reset emails).\n- 📨 Manage campaign (bulk) emails from the API.\n- 🎨 Edit and create templates to control the over all look and feel of campaigns.\n- 📝 Create, edit and delete lists.\n\n## Installation\n\nJust `pip install listmonk`\n\n## Usage\n\n```python\n\nimport pathlib\nimport listmonk\nfrom typing import Optional\n\nlistmonk.set_url_base('https://yourlistmonkurl.com')\n\nlistmonk.login('sammy_z', '1234')\nvalid: bool = listmonk.verify_login()\n\n# Is it alive and working?\nup: bool = listmonk.is_healthy()\n\n# Create a new list\nnew_list = listmonk.create_list(list_name=\"my_new_list\")\n\n# Read data about your lists\nlists: list[MailingList] = listmonk.lists()\nthe_list: MailingList = listmonk.list_by_id(list_id=7)\n\n# Various ways to access existing subscribers\nsubscribers: list[Subscriber] = listmonk.subscribers(list_id=9)\n\nsubscriber: Subscriber = listmonk.subscriber_by_email('testuser@some.domain')\nsubscriber: Subscriber = listmonk.subscriber_by_id(2001)\nsubscriber: Subscriber = listmonk.subscriber_by_uuid('f6668cf0-1c...')\n\n# Create a new subscriber\nnew_subscriber = listmonk.create_subscriber(\n    'testuser@some.domain', 'Jane Doe',\n    {1, 7, 9}, pre_confirm=True, attribs={...})\n\n# Change the email, custom rating, and add to lists 4 \u0026 6, remove from 5.\nsubscriber.email = 'newemail@some.domain'\nsubscriber.attribs['rating'] = 7\nsubscriber = listmonk.update_subscriber(subscriber, {4, 6}, {5})\n\n# Confirm single-opt-ins via the API (e.g. for when you manage that on your platform)\nlistmonk.confirm_optin(subscriber.uuid, the_list.uuid)\n\n# Disable then re-enable a subscriber\nsubscriber = listmonk.disable_subscriber(subscriber)\nsubscriber = listmonk.enable_subscriber(subscriber)\n\n# Block (unsubscribe) them\nlistmonk.block_subscriber(subscriber)\n\n# Fully delete them from your system\nlistmonk.delete_subscriber(subscriber.email)\n\n# Send an individual, transactional email (e.g. password reset)\nto_email = 'testuser@some.domain'\nfrom_email = 'app@your.domain'\ntemplate_id = 3  # *TX* template ID from listmonk\ntemplate_data = {'full_name': 'Test User', 'reset_code': 'abc123'}\n\nstatus: bool = listmonk.send_transactional_email(\n    to_email, template_id, from_email=from_email,\n    template_data=template_data, content_type='html')\n\n# Optional plaintext fallback for multipart HTML emails.\nstatus = listmonk.send_transactional_email(\n    to_email,\n    template_id,\n    from_email=from_email,\n    template_data=template_data,\n    content_type='html',\n    altbody='Plaintext order summary for mail clients that prefer text.'\n)\n\n# You can also add one or multiple attachments with transactional mails\nattachments = [\n    pathlib.Path(\"/path/to/your/file1.pdf\"),\n    pathlib.Path(\"/path/to/your/file2.png\")\n]\n\nstatus: bool = listmonk.send_transactional_email(\n    to_email,\n    template_id,\n    from_email=from_email,\n    template_data=template_data,\n    attachments=attachments,\n    content_type='html',\n    altbody='Plaintext fallback body'\n)\n\n# Access existing campaigns\nfrom listmonk.models import Campaign\nfrom datetime import datetime, timedelta\n\ncampaigns: list[Campaign] = listmonk.campaigns()\ncampaign: Campaign = listmonk.campaign_by_id(15)\n\n# Create a new Campaign\nlistmonk.create_campaign(name='This is my Great Campaign!',\n                         subject=\"You won't believe this!\",\n                         body='\u003cp\u003eSome Insane HTML!\u003c/p\u003e',  # Optional\n                         alt_body='Some Insane TXT!',  # Optional\n                         send_at=datetime.now() + timedelta(hours=1),  # Optional\n                         template_id=5,  # Optional Defaults to 1\n                         list_ids={1, 2},  # Optional Defaults to 1\n                         tags=['good', 'better', 'best']  # Optional\n                         )\n\n# Update A Campaign\ncampaign_to_update: Optional[Campaign] = listmonk.campaign_by_id(15)\ncampaign_to_update.name = \"More Elegant Name\"\ncampaign_to_update.subject = \"Even More Clickbait!!\"\ncampaign_to_update.body = \"\u003cp\u003eThere's a lot more we need to say so we're updating this programmatically!\"\ncampaign_to_update.altbody = \"There's a lot more we need to say so we're updating this programmatically!\"\ncampaign_to_update.lists = [3, 4]\n\nlistmonk.update_campaign(campaign_to_update)\n\n# Delete a Campaign\ncampaign_to_delete: Optional[Campaign] = listmonk.campaign_by_id(15)\nlistmonk.delete_campaign(campaign_to_delete)\n\n# Preview Campaign\npreview_html = listmonk.campaign_preview_by_id(15)\nprint(preview_html)\n\n# Access existing Templates\nfrom listmonk.models import Template\ntemplates: list[Template] = listmonk.templates()\ntemplate: Template = listmonk.template_by_id(2)\n\n# Create a new Template for Campaigns\nnew_template = listmonk.create_template(\n    name='NEW TEMPLATE',\n    body='\u003cp\u003eSome Insane HTML! {{ template \"content\" . }} \u003c/p\u003e',\n    type='campaign',\n)\n\n# Update A Template\nnew_template.name = \"Bob's Great Template\"\nlistmonk.update_template(new_template)\n\n# Delete a Template\nlistmonk.delete_template(3)\n\n# Preview Template\npreview_html = listmonk.template_preview_by_id(3)\nprint(preview_html)\n\n# Create a new template for Transactional Emails\nnew_tx_template = listmonk.create_template(\n    name='NEW TX TEMPLATE',\n    subject='Your Transactional Email Subject',\n    body='\u003cp\u003eSome Insane HTML! {{ .Subscriber.FirstName }}\u003c/p\u003e',\n    type='tx',\n)\n```\n\n## F.A.Q.\n\n### I got httpx2.HTTPStatusError: Client error '403 Forbidden'\n\nIf you encounter an error like this in your console:\n\n```text\nhttpx2.HTTPStatusError: Client error '403 Forbidden' for url 'https://yoursite.local/api/subscribers?page=1\u0026per_page=100\u0026query=subscribers.email='john@example.com''\n```\n\nIt means the authenticated user doesn’t have sufficient permissions to run SQL queries on subscriber data.\n\n**Solution:** Check the role assigned to your user. It must include the `subscribers:sql_query` permission to allow executing SQL queries on subscriber data. You can review and update user roles in your system’s admin panel. [[Reference](https://listmonk.app/docs/roles-and-permissions/#user-roles)]\n\n### I got an SSL certificate verification error against my self-hosted Listmonk\n\nAs of the move to [httpx2](https://github.com/pydantic/httpx2), TLS certificates are validated against your **operating system's trust store** (via the `truststore` package) instead of the bundled `certifi` CA list. If you self-host Listmonk behind a custom or corporate Certificate Authority you may see an error like:\n\n```text\nssl.SSLCertVerificationError: certificate verify failed: unable to get local issuer certificate\n```\n\n**Solution:** Install your CA certificate into your operating system's trust store, or point the client at your CA bundle via the standard environment variable before using the library:\n\n```bash\nexport SSL_CERT_FILE=/path/to/your-ca-bundle.pem   # or SSL_CERT_DIR=/path/to/ca-dir\n```\n\n## Want to contribute?\n\nPRs are welcome. But please open an issue first to see if the proposed feature fits with the direction of this library.\n\nEnjoy.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeckennedy%2Flistmonk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikeckennedy%2Flistmonk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeckennedy%2Flistmonk/lists"}