Why do my app's emails link to localhost after deploying?
A mailer runs in a background job with no incoming request, so it cannot infer your domain. It reads APP_HOST instead, and without that set it falls back to the development default. Set APP_HOST to your domain, redeploy, and every mailer link, canonical tag and sitemap URL becomes absolute and correct.
Set it and confirm it arrived
bin/kamal app exec 'bin/rails runner "puts Rails.application.config.x.app_host"'
If that prints nothing, the variable is not reaching the container. APP_HOST goes in the env
section of config/deploy.yml rather than in .kamal/secrets, because it is not a secret: it is
your public domain name.
Why this only breaks in production
In development every link you click carries a request, and Rails builds URLs from it. A mailer is
different: deliver_later enqueues a job, Solid Queue runs it minutes later in a different process,
and there is no request anywhere in that path. The host has to come from configuration.
That is also why the failure is invisible in the test suite. Request specs supply a host, so links look right, and the first broken link is the first real sign-in email a user receives.
The blast radius is wider than email
The same setting feeds several things that all need an absolute URL and none of which have a request:
- Magic-code sign-in links, which is the one users hit immediately.
<link rel="canonical">on every public page./sitemap.xml,/feed.xmland/llms.txt, which are built byapp/controllers/seo_controller.rb.
A sitemap full of localhost URLs is submitted successfully and indexes nothing, with no error
anywhere.
Verify from outside
curl -s https://yourdomain.com/sitemap.xml | head -5
The first <loc> should be your domain. That single check covers the mailer case too, because both
read the same configured host.
Do not hardcode it in a mailer
It is tempting to pass host: into one *_url call and move on. That fixes one link and leaves the
other dozen, and it puts the domain in application code where a rebrand has to find it. One setting,
read everywhere, is the shape that stays correct.