Part of the PurelyManage series.

Listing Users

The Users page shows all email accounts across all your domains. The list is served from a local PostgreSQL cache rather than a live PurelyMail API call on every page load.

The reason is speed and rate limits. PurelyMail’s listUser endpoint returns all users in one call, but calling it on every page load when you have 50+ users and the page auto-refreshes every 60 seconds is wasteful. The cache (purelymail_users table) is populated on first boot and kept in sync by a background cron that runs a full refresh daily at 2am. When a user is created or deleted through the panel, the cache is updated immediately so the UI reflects the change without waiting for the cron.

The page includes a live search field that filters by partial match on the email address and shows a count of matching results.

Creating a User

The create user form has three fields: domain (a dropdown populated from your PurelyMail domains), username (the local part of the email), and password.

The password field has two modes. You can type one yourself, or use the built-in generator. The generator produces a strong random password and fills the field automatically. A strength indicator updates as you type, giving you immediate feedback on password quality. There is a copy-to-clipboard button next to the field so you can grab the password before submitting.

The request to PurelyMail disables the built-in password reset email and welcome email, since you are managing users as a sysadmin and likely communicating credentials out-of-band:

await pmPost('/api/v0/createUser', {
  userName,
  domainName,
  password,
  enablePasswordReset: false,
  sendWelcomeEmail: false,
})

After creation the new user is added to the local cache immediately, so it appears in the list without a page reload.

Managing Existing Users

Clicking a user opens a manage modal with two actions: toggle 2FA and reset password.

2FA Toggle

2FA is toggled via modifyUser with the enableTwoFactor field. The toggle updates immediately in the UI via React Query cache invalidation, so the button reflects the new state without a full refetch.

await pmPost('/api/v0/modifyUser', { userName, enableTwoFactor: true })

Password Reset

Resetting a password sends a modifyUser call with the newPassword field. The correct field name was not immediately obvious: the API accepts password and passwordChangeKey without error, but neither actually changes the password. Only newPassword works.

// The only field that actually changes the password:
await pmPost('/api/v0/modifyUser', { userName, newPassword })

After the reset, the new password is displayed in the modal with a copy button. One early bug: clearing the password field in state immediately after the API call succeeded caused the field to go blank before the user had a chance to copy it. The fix was to keep the value in state until the user explicitly closes the modal or requests another reset.

The clipboard copy also has a fallback. On HTTP origins (local development without TLS), navigator.clipboard.writeText is blocked by the browser. A fallback using document.execCommand('copy') handles those cases.

Deleting a User

Deleting a user follows the same 24-hour queue as domain and routing rule deletions. The delete button on the Users page schedules a deletion rather than executing immediately. The button is replaced with a grayed-out “Pending” indicator for any user already in the queue.

The actual deletion calls deleteUser on the PurelyMail API and removes the entry from the local cache when the cron executes it.

App Passwords

App passwords were on the original feature list. The PurelyMail API has createAppPassword and deleteAppPassword endpoints. Both consistently return success with every parameter combination attempted. No app password was ever actually created.

Every plausible field name was tried: userName, user, email, description, label, name. The API accepted them all silently. Without source access or official documentation there was no path forward, so app password management was removed from scope. If you need to manage app passwords, you can do so directly through PurelyMail.


The next post covers how the DNS health scheduler works: a priority-based system for keeping DNS status current across many domains without hammering the PurelyMail API.