English
White label
A Mankomail instance can carry another brand than its own: your name, your logos, your colors. There are two ways to set it.
- Self-hosted: environment variables (
BRAND_*), read at boot. - Linked to a control plane (a fleet of instances operated together): the brand configured in the control plane's back office, received by the instance and applied without a restart.
When both exist, the control plane wins field by field: a field it does not define keeps the environment value, and otherwise the product default.
Where the brand shows
| Element | Where it appears | Default |
|---|---|---|
| Name | Sidebar, sign-in and invitation pages, browser tab title, system emails | Mankomail |
| Logo (light, dark) | Sidebar, sign-in page. A logo replaces the monogram and the name text next to it | The monogram |
| Favicon | Browser tab | The monogram, drawn in the primary color when there is one |
| Primary color | The theme accent: primary buttons, active navigation item, links, focus ring | The theme's accent |
| Accent color | Sign-in page panel | — |
| Help link | Sign-in page, member menu, suspension banner | None |
| “Powered by Mankomail” | Sign-in page, system emails. Shown only when the brand name differs from the product name | Shown |
| Sign-in page text and image | Subtitle and left panel of the sign-in page | The product text, no image |
| Email sender name and footer | Approval request emails | The brand name, no footer |
| Custom domain | Links generated in emails (approval buttons, invitation links) | PUBLIC_BASE_URL |
The last three rows can only be set from a control plane.
Colors stay readable
A brand color is not always readable as an interface color: a dark red is fine on a light page and unreadable on a dark one, a pale yellow the opposite. The instance keeps the hue of the primary color and recomputes its lightness for each of the three themes, in light and in dark mode, so that text in the accent color stays at 4.5:1 against the page, button labels stay readable, and the focus ring stays visible. The color you see may therefore be slightly lighter or darker than the one you set.
The computed colors are kept in the browser, so that the next page load shows them from the first frame.
Self-hosted: environment variables
Set the variables in .env, then recreate the application container:
bash
BRAND_NAME="Acme Mail"
BRAND_LOGO_URL=https://cdn.acme.example/logo.svg
BRAND_LOGO_DARK_URL=https://cdn.acme.example/logo-dark.svg
BRAND_FAVICON_URL=https://cdn.acme.example/favicon.png
BRAND_PRIMARY_COLOR=#7A1F35
BRAND_ACCENT_COLOR=#FFE680
BRAND_SUPPORT_URL=https://help.acme.example
BRAND_HIDE_POWERED_BY=falsebash
docker compose -f compose.reference.yaml up -d app- Images must be reachable by the users' browsers. Use
httpsURLs: the page's security policy allowshttps:images, plus the exact origin of anhttp:URL set in these variables. - An invalid value (a color that is not
#RRGGBB, a malformed URL) is ignored with aconfiguration:line in the boot log; the default applies.
The full list is in Environment variables.
Linked to a control plane
A control plane is a separate service that operates a fleet of instances (one per customer organisation): it receives their usage, sends them their brand, plan and entitlements, and can suspend them. The instance only makes outgoing HTTPS calls; nothing ever connects to it.
The link is on only when the three variables are set together:
bash
CONTROL_PLANE_URL=https://api.example.com/api/instances/v1
CONTROL_PLANE_INSTANCE_ID=ins_01k6x…
CONTROL_PLANE_SECRET_FILE=/run/secrets/control_plane_secretWithout them, the instance calls nothing and sends nothing anywhere. If only one or two are set, the link stays off and the boot log names the missing one.
What the instance sends and receives
Every call is signed with the shared secret (HMAC-SHA256 over the method, path, timestamp, a single-use nonce and the body). The machine clock must be within five minutes of real time: run NTP.
| Call | Frequency | Content |
|---|---|---|
| Heartbeat | Every minute | Version and health: database, pending migrations, job queue delay, mailboxes in error |
| Usage | Every five minutes | Hourly totals: executions and steps by final status, emails received and sent by provider, connected mailboxes, active members (seen in the last 30 days), AI tokens and cost by provider and model, storage, API calls |
| Configuration | Every five minutes, and as soon as the heartbeat announces a change | Brand, plan, entitlements, instance status |
Usage is counted from the instance's own database. It carries no email content, no address and no subject: only counts.
When the control plane is unreachable
The instance keeps working:
- the last valid configuration stays applied (it is stored in the database);
- failed calls are retried with an increasing delay, up to 30 minutes;
- usage hours that were not acknowledged stay queued and are sent when the link comes back, oldest first. Each hour is reported as a total that replaces the previous one, so sending it twice never counts it twice.
Suspension
When the control plane suspends the instance, it switches to read-only:
- every user sees a red banner explaining the situation, with the help link when there is one;
- the API refuses changes with the error
instance.suspended(signing in and out still work); - incoming webhooks receive
503withRetry-After, so that the sender retries later instead of losing them; - workflows, synchronisation and sending are paused. Nothing is lost: jobs stay queued and resume when the suspension is lifted.
Plan and entitlements
The plan and entitlements received are visible to administrators and readable by the instance, but they do not restrict any feature yet. The quotas set in environment variables still apply.
Checking the result
Administration › Instance (administrators only) shows:
- whether the link is configured, the announced status, and for each call its last success and last error, in plain words;
- the number of usage hours waiting to be sent;
- the plan and entitlements received;
- every brand field with its value and its origin (control plane, environment, default) and, for the ones set by environment, the variable to change.
Nothing is editable on this page: the brand changes in the control plane's back office, or in the environment variables followed by a restart.