Repository navigation
fix(deploy): plan and apply refuse an unset or example email.from - #132
Merged
Merged
Conversation
Every service runs with APP_ENV=production, and the apps refuse to boot with an unset FROM_EMAIL or one on a reserved example/test domain (#103). deploy/ defaulted email.from to noreply@example.com, so a fresh make railway-setup on defaults would deploy apps that never boot. - platform: RealSender, the apps' exact rule (example.com/.net/.org, example, test, invalid, localhost; "Name <a@b>" allowed), and SenderProblems per environment (email.from or per_environment.<env>.from_email; manual is not checked). email.from now defaults to unset. - railway-setup: plan, setup and apply refuse before touching anything, with a next step; apply on a terminal without --yes asks for the sender and writes it into platform.yaml. New --email-from / PLATFORM_EMAIL_FROM (platform.Edit now sets dotted keys). doctor fails the email.from check. - docs/deploy.md and AGENTS.md: a real sender is required. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton
added a commit
that referenced
this pull request
Oct 23, 2026
* fix(config): production refuses an unset or example FROM_EMAIL Both apps fell back to noreply@example.com when FROM_EMAIL was unset, and accepted it in production, where no mail provider sends from it: every verification, reset and invite email would fail, visible only in the log. In production the web and admin configs now refuse an unset FROM_EMAIL and any sender on a reserved example or test domain (RFC 2606/6761), in either "a@b" or "Name <a@b>" form, so the deploy fails its boot with the reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(smoke): the release smoke boots with a FROM_EMAIL off the example domains Production now refuses an unset or example sender, so the smoke (which boots with only what production requires) sets one. Nothing is sent: the Resend key is a dummy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(config): point FROM_EMAIL's checks at each other The apps' realSender and deploy/platform's reservedSenderDomains (#132) refuse the same domains; both now say so. docs/deploy.md links to #132's paragraph instead of repeating it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
#103 makes web and admin refuse to boot in production with an unset
FROM_EMAILor one on a reserved example/test domain. Every Railway service runs withAPP_ENV=production, anddeploy/defaultedemail.fromtonoreply@example.com, so a freshmake railway-setupon defaults would deploy apps that never boot. This makes the deploy side refuse first. It goes in before #103.Evidence
Read-only
bin/railway-setupruns against a scratchplatform.yaml(staging,production; projectgfs-senderprobe-261023, which does not exist and was never created:railway listshows 0).plan --jsonrefusing to deploy apps that would not boot: production needs a real FROM_EMAIL (staging: email.from is not set; production: email.from is not set): set email.from in deploy/platform.yaml …and nextSteps[0]Set a real sender for auth emails: …noreply@example.complan --jsonstaging: "noreply@example.com" is an example or test address; production: …"Acme <noreply@acme.dev>"+per_environment.staging.from_email: qa@mail.testplan --jsonstaging: "qa@mail.test" is an example or test address"Acme <noreply@acme.dev>"plan --json9 change(s) pending(a normal plan)apply --yes --json < /dev/null"project": null, the nextSteps entry; nothing createdplan --email-from noreply@acme.devplatform.yaml: set email.from (commit it); the file now hasfrom: noreply@acme.dev, exit 2doctor --jsonemail.fromcheckfailmake check-fastok,make deploy-varsok (44 app variables),make lint-layeringok.No unit tests, on purpose: the brief asked for tests in
deploy/platform, butscripts/check-test-boundaries.sh(AGENTS.md "Test boundaries", mandatory) allows tests only in the five service/handler/auth directories and rejects any_test.goindeploy/.deploy/has no tests on main. The runs above cover the unset, example and real-sender cases instead. To get tests here, JJ would have to sign off on changing that rule.Merge Danger
Door: two-way.
Blast Radius: deploys
Projects whose
platform.yamlstill saysnoreply@example.com(or has no sender) now get a refused plan/apply with the fix spelled out. That is intended: with #103 their apps would not boot. Amanualfrom_emailis not checked, because its value lives in Railway.🤖 Generated with Claude Code