APP_NAME is a runtime variable, and two of the three places showing the name ignored it.
The sign-in page fetched /api/config, received the name, and used only sourceUrl — so a rebranded deployment still said ihasmail on the one page a new user meets first. The top bar had it written in. Only the document title read it, and it had been taking it from the session all along.
The rebranding guide documents both as things to patch yourself, one of them with "If you change nothing else on this page, change this." It should not have to.
What changed
The sign-in page takes the name from the answer it was already getting. The top bar takes it from the session, where the title has taken it from since it was written. Neither adds a request.
One shared DEFAULT_APP_NAME rather than the string written out at three call sites — three copies of a default is how two of them end up stale.
It stands if the config request fails, because a sign-in form with no name on it would be worse than one with the wrong name. An empty or non-string name falls back too, so a deployment that sets APP_NAME= does not get a nameless page.
Verified
Ran the mock with APP_NAME="Acme Mail":
Before
After
Sign-in heading
ihasmail
Acme Mail
Top bar
ihasmail
Acme Mail
Tab title
Acme Mail
Acme Mail
Five tests on the fallback shape — server name used, trimmed, and the four ways it can be absent.
npm run typecheck, npm test (1000 web + 142 server), npm run build pass.
Follow-up
rebranding.md on the docs site now describes two things that are no longer true. Separate PR in the site repo.
`APP_NAME` is a runtime variable, and two of the three places showing the name ignored it.
The **sign-in page** fetched `/api/config`, received the name, and used only `sourceUrl` — so a rebranded deployment still said **ihasmail** on the one page a new user meets first. The **top bar** had it written in. Only the document title read it, and it had been taking it from the session all along.
The rebranding guide documents both as things to patch yourself, one of them with *"If you change nothing else on this page, change this."* It should not have to.
## What changed
The sign-in page takes the name from the answer it was **already getting**. The top bar takes it from the session, where the title has taken it from since it was written. Neither adds a request.
One shared `DEFAULT_APP_NAME` rather than the string written out at three call sites — three copies of a default is how two of them end up stale.
It stands if the config request fails, because a sign-in form with no name on it would be worse than one with the wrong name. An empty or non-string name falls back too, so a deployment that sets `APP_NAME=` does not get a nameless page.
## Verified
Ran the mock with `APP_NAME="Acme Mail"`:
| | Before | After |
| --- | --- | --- |
| Sign-in heading | ihasmail | **Acme Mail** |
| Top bar | ihasmail | **Acme Mail** |
| Tab title | Acme Mail | Acme Mail |
Five tests on the fallback shape — server name used, trimmed, and the four ways it can be absent.
`npm run typecheck`, `npm test` (1000 web + 142 server), `npm run build` pass.
## Follow-up
`rebranding.md` on the docs site now describes two things that are no longer true. Separate PR in the site repo.
**Merged** 2026-09-02 as coffey-labs/ihasmail@93856de14311
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
APP_NAMEis a runtime variable, and two of the three places showing the name ignored it.The sign-in page fetched
/api/config, received the name, and used onlysourceUrl— so a rebranded deployment still said ihasmail on the one page a new user meets first. The top bar had it written in. Only the document title read it, and it had been taking it from the session all along.The rebranding guide documents both as things to patch yourself, one of them with "If you change nothing else on this page, change this." It should not have to.
What changed
The sign-in page takes the name from the answer it was already getting. The top bar takes it from the session, where the title has taken it from since it was written. Neither adds a request.
One shared
DEFAULT_APP_NAMErather than the string written out at three call sites — three copies of a default is how two of them end up stale.It stands if the config request fails, because a sign-in form with no name on it would be worse than one with the wrong name. An empty or non-string name falls back too, so a deployment that sets
APP_NAME=does not get a nameless page.Verified
Ran the mock with
APP_NAME="Acme Mail":Five tests on the fallback shape — server name used, trimmed, and the four ways it can be absent.
npm run typecheck,npm test(1000 web + 142 server),npm run buildpass.Follow-up
rebranding.mdon the docs site now describes two things that are no longer true. Separate PR in the site repo.Merged 2026-09-02 as coffey-labs/ihasmail@93856de143
Rebuilt from: git history, session transcript.