Listmonk

A resource-oriented Ruby client for the listmonk HTTP API.

Installation

Add the gem to your bundle:

bundle add listmonk

The gem requires Ruby 3.3 or newer.

Configuration

Listmonk supports Basic authentication and its Authorization: token header. Basic authentication is the default:

client = Listmonk::Client.new(
  base_url: "https://newsletter.example.com",
  username: ENV.fetch("LISTMONK_USERNAME"),
  token: ENV.fetch("LISTMONK_TOKEN")
)

Use token-header authentication when needed:

client = Listmonk.client(
  base_url: "https://newsletter.example.com/api",
  username: ENV.fetch("LISTMONK_USERNAME"),
  token: ENV.fetch("LISTMONK_TOKEN"),
  auth: :token,
  timeout: 30,
  open_timeout: 10
)

The client accepts a server root or an URL ending in /api. Credentials may be omitted for public endpoints.

Usage

Every method returns a Listmonk::Response. Use data for the API payload, or inspect status, headers, and body when needed.

response = client.subscribers.list(page: 1, per_page: 50, list_id: [1, 2])
subscribers = response.data.fetch("results")

subscriber = client.subscribers.create(
  email: "reader@example.com",
  name: "A Reader",
  lists: [1],
  attribs: {source: "website"}
).data

client.subscribers.update(subscriber.fetch("id"), name: "Reader")
client.subscribers.send_optin(subscriber.fetch("id"))

Campaigns and transactional messages:

campaign = client.campaigns.create(
  name: "July news",
  subject: "What's new",
  lists: [1],
  from_email: "News <news@example.com>",
  content_type: "html",
  messenger: "email",
  type: "regular"
).data

client.campaigns.create_content(campaign.fetch("id"), body: "<h1>Hello</h1>")
client.campaigns.start(campaign.fetch("id"))

client.transactional.deliver(
  template_id: 3,
  subscriber_email: "reader@example.com",
  data: {confirmation_url: "https://example.com/confirm"}
)

Subscriber imports and media uploads use multipart requests:

client.imports.create(
  file: "/tmp/subscribers.zip",
  params: {
    mode: "subscribe",
    subscription_status: "confirmed",
    lists: [1],
    overwrite: true
  }
)

client.media.upload(file: "/tmp/banner.png", content_type: "image/png")

Resources cover all operations in the published Swagger collection:

  • miscellaneous, settings, admin, and logs
  • subscribers, lists, imports, and bounces
  • campaigns, templates, media, and transactional
  • maintenance and public

For an undocumented or newly added endpoint, use the low-level request method:

client.request(:get, "new-endpoint", params: {page: 1})
client.request(:post, "new-endpoint", json: {enabled: true})

Errors

Non-successful responses raise typed exceptions. Every HTTP exception exposes status, body, and response.

begin
  client.lists.retrieve(999)
rescue Listmonk::NotFoundError => error
  warn "List not found: #{error.body.inspect}"
rescue Listmonk::RateLimitError
  # Retry with application-specific backoff.
end

Connection failures raise Listmonk::ConnectionError, timeouts raise Listmonk::TimeoutError, and malformed JSON raises Listmonk::ParseError.

Development

Install dependencies and run the complete verification task:

bin/setup
bundle exec rake

RSpec uses WebMock for request-level tests and SimpleCov for coverage.

Docker integration tests

Run the opt-in integration suite against an ephemeral Listmonk 6.1.0 and PostgreSQL 17 environment:

bundle exec rake integration

The task starts Docker Compose on 127.0.0.1:19000, creates a temporary API user, runs live list, subscriber, template, authentication, and health checks, then removes the containers and database volume. Override the defaults with LISTMONK_PORT or LISTMONK_IMAGE.

Normal bundle exec rake runs only the WebMock suite and does not require Docker.

Releasing

Publishing uses RubyGems trusted publishing, so no long-lived RubyGems API key is stored in GitHub.

Before the first release, create a pending trusted publisher in your RubyGems.org profile with:

  • Gem name: listmonk
  • Repository owner: polydice
  • Repository name: listmonk-ruby
  • Workflow filename: release.yml
  • Environment: release

To publish a version:

  1. Update lib/listmonk/version.rb and CHANGELOG.md.
  2. Run bundle exec rake, bundle exec rake integration, and bundle exec rbs validate.
  3. Run bundle exec rake build and inspect the generated package under pkg/.
  4. Commit the release and create a matching version tag, for example git tag v0.1.0.
  5. Push main and the tag. The Publish gem GitHub workflow validates that the tag matches Listmonk::VERSION and publishes the gem.

License

The gem is available under the terms of the MIT License.