(open source) PMG Quarantine Admin - mobile-first admin console for PMG (quarantine, tracking center, dashboard) + live demo

ikrsdo

Member
Aug 25, 2023
22
2
8
Hello PMG Admins,

I've been running PMG for a while, and the one thing that always bugged me was managing the spam quarantine from my phone. The admin interface works fine, but it's not built for a small screen - and there are days I need to check something quickly without sitting down at my computer.

It's grown a fair bit since I first posted this, so here's the full picture.

It's a single Docker container, talks to PMG over the API only - doesn't touch the appliance itself. Runs alongside PMG, not on it.

Features
  • Dashboard - 7-day overview on login: quarantine volume, delivery status, top senders/receivers
  • Quarantine management - all three types (Spam, Virus, Attachment), list/search/filter, deliver/whitelist/block, swipe-able cards and multi-select bulk actions on mobile, dense table on desktop. The block action requires confirmation.
  • Tracking Center - read-only lookup by sender/recipient/status. Each entry's syslog trail is shown as a structured, expandable Message Events timeline (Received/Processed/Queued/Policy Match/Delivered/etc.) instead of raw log lines.
  • Cross-linking between a Quarantine message and its best-effort matching Tracking Center entry, and back - the two PMG APIs share no common identifier, so this is sender/recipient + a time window, not guaranteed.
  • Saved filter presets and CSV export on both list pages.
  • Per-admin PMG login (Help Desk role) - no shared service account, PMG's own audit log attributes actions to the right admin.
  • Dark/light theme, installable as a PWA.
  • Update-check banner - notifies in-app when a newer release is on GitHub, dismissible per version.
  • Demo mode - see below.
Out of scope: welcomelist/blocklist policy management (global or per-domain) - PMG's own UI already covers that well.

Live demo
https://pmg-quarantine-demo.mcs.net.tr/

Login: demo / demo

Runs against an in-memory fake PMG, not a real server - every screen works, quarantine actions really mutate the mock data, and it resets whenever the container restarts. Separate, isolated instance, has nothing to do with any real deployment.

Security notes
  • No PMG credentials are ever stored, in .env, on disk, or in the browser - only the short-lived session ticket, kept server-side.
  • /api/login is rate-limited against credential brute-forcing.
  • Every quarantine action is checked against a fixed whitelist before being forwarded to PMG - the UI only exposes deliver/whitelist/block today, the whitelist itself covers the full set of valid PMG actions.
  • Security headers set on every response (Helmet), Docker image runs as non-root, dependencies audited before each release.
  • CSV export is sanitized against formula/CSV injection.

Tech stack
Node.js/Express backend (auth + PMG API proxy, since the PMG API has no CORS and the ticket/CSRF flow needs to stay server-side), React + Tailwind frontend, single multi-stage Dockerfile.

MIT licensed, open source:
https://github.com/ikrsdo/pmg-quarantine-admin

Feedback welcome, especially if you're running PMG and this is missing something you'd want.
 
Last edited:
hi, nice work.

Did you consider sending patches directly instead of making a standalone thing?

While we're probably wouldn't integrate react+vite, we're using our own rust based ui framework (that we use e.g. for the user quarantine mobile view) that could replicate most of this i reckon.

Also some things might be nice to have in the regular desktop view too (parsed tracking center messages, etc.)

EDIT: in case you want to help getting some of these into the main product, here is the developer docs https://pmg.proxmox.com/wiki/Developer_Documentation
 
hi, nice work.

Did you consider sending patches directly instead of making a standalone thing?

While we're probably wouldn't integrate react+vite, we're using our own rust based ui framework (that we use e.g. for the user quarantine mobile view) that could replicate most of this i reckon.

Also some things might be nice to have in the regular desktop view too (parsed tracking center messages, etc.)

EDIT: in case you want to help getting some of these into the main product, here is the developer docs https://pmg.proxmox.com/wiki/Developer_Documentation

Hi Dominik,

Thanks, glad it's useful - and glad the parsed tracking center messages specifically caught your eye, that's the part I'm happiest with too :)

The project's grown quite a bit since I first posted this (see the updated first post above, plus a live demo now if you want to click through it without setting anything up).

On patches - I built this in React/Node (with the help from Claude Code) and don't have Rust experience, so a direct contribution to your UI framework isn't something I can do myself right now.

What I can offer: the logic behind the structured Message Events view - how I parse pmg-smtp-filter's syslog lines and bucket them into Received/Processed/Queued/Policy Match/Delivered/Deferred/Bounced/Rejected/Greylisted, plus how I handle the two different syslog timestamp formats I ran into (classic Postfix vs ISO 8601). Happy to write that up - categories, patterns, the edge cases I hit - if it saves your team time re-deriving it, even if the actual implementation ends up being Rust on your side.

One more thing that might be worth mentioning: I also added best-effort cross-linking between a Quarantine entry and its matching Tracking Center entry - the two PMG APIs don't share a common identifier, so it currently matches on sender/recipient plus a time window, which isn't fully reliable. If there's ever a shared identifier between quarantine and tracking on the PMG side, that link could become exact instead of best-effort - figured that's worth flagging either way.

Diving into the developer docs and finding a contribution isn't something I can realistically commit time to right now. But I'll admit it's tempting - I've never had the chance to be part of a project built by a team like yours :)

Thanks again for taking the time to look at this.