Summary
Two problems with the webmail white-label config, found after branding a deployment end to end. Four of the six fields work. The other two are accepted, validated and persisted by the API but have no effect anywhere, and the parts of the page that most obviously need white-labeling are not covered by the schema at all.
Openship 0.6.5, ghcr.io/oblien/openship-webmail:latest, self-hosted on the mail server.
1. siteTitle and siteDescription are write-only
PATCH /admin/branding accepts both, enforces their zod limits, and persists them — /branding.json reads back:
{
"siteTitle": "Contribute Club eMail",
"siteDescription": "Mail Server for CC",
"loginHeading": "Contribute Club",
"loginSubtext": "Sign in with your mailbox credentials",
"loginFooter": "Powered by <redacted>",
"homeHtml": null
}
The served page ignores both:
$ curl -s https://<host>/ | grep -o '<title>[^<]*</title>'
<title>OpenShip Mail</title>
They are static literals in the prebuilt /app/client/index.html:
<title>OpenShip Mail</title>
<meta name="description" content="Your self-hosted mailbox."/>
<meta property="og:title" content="OpenShip Mail"/>
<meta property="og:description" content="Your self-hosted mailbox."/>
siteTitle appears nowhere in the render path — the only files mentioning it in the image are server/src/lib/branding.ts and server/src/routes/branding-admin.ts, i.e. storage and transport only. loginHeading, loginSubtext and loginFooter do render, because those are applied client-side from /branding.json.
Net effect: an operator sets a site title, the API returns 200, /branding.json confirms it, and the browser tab, bookmarks, and every link preview still say "OpenShip Mail". Nothing signals that two of the six fields are inert.
Either apply them (inject into the document head from /branding.json, the way the login strings already are), or drop them from the schema so the API stops accepting values it cannot honour. Applying them is much the better outcome — the tab title and OG tags are exactly what a white-label needs.
2. The vendor footer is outside the branding schema
The login page renders, below the operator's own loginFooter:
e.jsx("span", { children: "Powered by" }),
e.jsx("a", { href: "https://openship.io", target: "_blank", rel: "noopener noreferrer", … })
plus Docs / Privacy / Terms / GitHub links. None are covered by any branding field, so a fully branded deployment still displays the vendor's name and links visitors off-site to it.
If white-labeling is a supported feature, a showPoweredBy / footerLinks toggle (or simply letting loginFooter replace that row rather than sit above it) would make it complete. If the attribution is intentional and required, saying so in the branding docs would save operators discovering it only after they have branded everything else — it is not mentioned in the catalog help text for these fields, which describes the feature as "white-label".
Working fields, for completeness
loginHeading, loginSubtext, loginFooter and homeHtml all behave correctly and take effect immediately. There is also no API to upload a logo or favicon, though BRANDING_PATH/assets/ exists and is served at /branding/assets/* — so those must be placed on disk out of band.
Related: #566, #567.
Summary
Two problems with the webmail white-label config, found after branding a deployment end to end. Four of the six fields work. The other two are accepted, validated and persisted by the API but have no effect anywhere, and the parts of the page that most obviously need white-labeling are not covered by the schema at all.
Openship 0.6.5,
ghcr.io/oblien/openship-webmail:latest, self-hosted on the mail server.1.
siteTitleandsiteDescriptionare write-onlyPATCH /admin/brandingaccepts both, enforces their zod limits, and persists them —/branding.jsonreads back:{ "siteTitle": "Contribute Club eMail", "siteDescription": "Mail Server for CC", "loginHeading": "Contribute Club", "loginSubtext": "Sign in with your mailbox credentials", "loginFooter": "Powered by <redacted>", "homeHtml": null }The served page ignores both:
They are static literals in the prebuilt
/app/client/index.html:siteTitleappears nowhere in the render path — the only files mentioning it in the image areserver/src/lib/branding.tsandserver/src/routes/branding-admin.ts, i.e. storage and transport only.loginHeading,loginSubtextandloginFooterdo render, because those are applied client-side from/branding.json.Net effect: an operator sets a site title, the API returns 200,
/branding.jsonconfirms it, and the browser tab, bookmarks, and every link preview still say "OpenShip Mail". Nothing signals that two of the six fields are inert.Either apply them (inject into the document head from
/branding.json, the way the login strings already are), or drop them from the schema so the API stops accepting values it cannot honour. Applying them is much the better outcome — the tab title and OG tags are exactly what a white-label needs.2. The vendor footer is outside the branding schema
The login page renders, below the operator's own
loginFooter:plus Docs / Privacy / Terms / GitHub links. None are covered by any branding field, so a fully branded deployment still displays the vendor's name and links visitors off-site to it.
If white-labeling is a supported feature, a
showPoweredBy/footerLinkstoggle (or simply lettingloginFooterreplace that row rather than sit above it) would make it complete. If the attribution is intentional and required, saying so in the branding docs would save operators discovering it only after they have branded everything else — it is not mentioned in the catalog help text for these fields, which describes the feature as "white-label".Working fields, for completeness
loginHeading,loginSubtext,loginFooterandhomeHtmlall behave correctly and take effect immediately. There is also no API to upload a logo or favicon, thoughBRANDING_PATH/assets/exists and is served at/branding/assets/*— so those must be placed on disk out of band.Related: #566, #567.