Repository navigation
Added an optional Mailpit for local sites - #351
Merged
Merged
Conversation
closes https://linear.app/ghost/issue/PLA-502/optional-mailpit-for-local-sites-install-local-with-mailpit A local site has no mail configured, so Ghost cannot deliver staff invites, password resets or member sign-in links, and sign-in links are what theme development needs most. `install --local --with mailpit` now runs Mailpit beside Ghost and points Ghost's SMTP settings at it, so that mail lands in a web inbox on the loopback interface. It is opt-in and local only. In production it would quietly swallow the site's real mail, so `--domain` with it is a usage error and validation rejects the profile beside `production`. Ghost's settings are written into ghost.env rather than set by compose.yml, because container-owned keys would override an operator's or an import's real SMTP; the lines are the operator's afterwards. Each site gets its own Mailpit, with its inbox port chosen the way Ghost's is and its messages kept in data/mailpit. An import may take it too, and only it: a local copy of a real site then sends nothing to real members. The source's mail transport is dropped and named, and its mail__from kept. Newsletters go through Mailgun's API, not SMTP, so Mailpit never sees them; the docs say so. - compose.yml: the mailpit service, pinned by digest, under its own profile, with a readiness health check and a unique network alias. - manager/src/site.ts, config.ts, undo.ts: the profile, the local-only rule, and clean-up of a failed install's Mailpit. - manager/src/commands/install.ts: --with mailpit, its port, ghost.env settings, data directory and summary line. labs__publicAPI is now set for ActivityPub only, not for any optional service. - manager/src/import.ts, import/config.ts: --with mailpit on import, replacing the source's mail transport. - manager/src/verify.ts, commands/site.ts: check and install verify Mailpit's health and its SMTP greeting from the ghost container; info prints the inbox URL. - tests/e2e/install.sh, import.sh: a password reset from Ghost arrives in Mailpit, for a new site and an imported one; the inbox survives a restart. - docs/install.md, configuration.md, bundle-v1.md, .env.example, AGENTS.md: documented.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes https://linear.app/ghost/issue/PLA-502/optional-mailpit-for-local-sites-install-local-with-mailpit
A local site has no mail configured, so staff invites, password resets and member sign-in links go nowhere.
./ghost-docker install --local --with mailpitruns Mailpit beside Ghost and points Ghost's SMTP settings at it, so that mail lands in a web inbox on127.0.0.1.--domainwith--with mailpitexits 2;config validaterejectsmailpitbesideproductioninCOMPOSE_PROFILES, where it would swallow real mail.ghost.env, not compose.yml'senvironment, which would override an operator's or an import's real SMTP. They are the operator's afterwards.data/mailpit. A non-emptydata/mailpitis refused like the other data directories.install --import --with mailpitis allowed, andmailpitis the only optional service an import takes. The source'smail__transportandmail__options__*are dropped (named, without values) and Mailpit's written instead;mail__fromis kept. A local copy of a real site then never mails real members.installandcheckrequire Mailpit's health check and its SMTP greeting atmailpit-<project>:1025from inside the ghost container. The summary andinfoprint the inbox URL.labs__publicAPIis now added for ActivityPub only, rather than for any optional service.Newsletters (including "send test email") go through Ghost's Mailgun provider, not SMTP, so Mailpit does not see them; the docs say so.
Tests
pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm test: 277 pass.tests/e2e/install.sh: passes on OrbStack. New step: install with Mailpit, set up the owner, request a password reset, and find the mail in Mailpit's API, before and after a restart. The existing port-conflict step was skipped for this run (port held in advance): it fails on OrbStack independently of this change, because the manager now refuses a host-held--portbefore Docker can; that test is being fixed separately.tests/e2e/import.sh: passes. New step: import with--with mailpit, check the replaced transport and keptmail__from, and catch the imported site's password-reset mail.🤖 Generated with Claude Code