Move the mailer out of the mail router #455
No reviewers
Labels
No labels
Kestra
bug
enhancement
someday
subtask
☁️ api
🎛️ infrastructure
🐞 sentry
📆 2025 Season
📝 pages
allpicks
📝 pages
picks
📝 pages
standings
🚀 performance
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
johnsturgeon/tgfp-web!455
Loading…
Reference in a new issue
No description provided.
Delete branch "move-the-mailer-out-of-the-mail-router-so-jobs-can-send-too-453"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Move only, no behaviour change.
What moved
app/mailer.pynow owns sending: theConnectionConfig, a shared_send(subject, recipients, template_name, body), andsend_welcome_email.app/routers/mail.pykeeps its two routes and imports from it.v2.pyimportsfrom
app.mailerinstead ofapp.routers.mail-- the router-importing-a-routerthat motivated the issue.
send_welcome_emailkeeps itsRequest. It is sent from routes only, andurl_foris the right way to build its links while a request is in hand.Left behind by the copy
Three things came along that are dead in a mailer and were removed:
EmailSchema-- an HTTP request-body model, belongs with the route thatparses it
router-- a secondAPIRouterwith the same/mailprefix, never includedtemplates-- the router renderssend_welcome.j2; the mailer renders nopages
Their imports went with them. The router also had a stale
ConnectionConfigimport and had lost the
template_folderitsJinja2Templatesreferenced, soit was failing at import until that came back with the right
.parent.parent.email_welcome.j2never used thediscord_img_urlkey the body passed it, sothat goes too.
Deliberately duplicated
template_folderis defined in both files, pointing at the same directory --the mailer needs it for
ConnectionConfig, the router for page rendering.Having the router import it from the mailer would be worse than the two lines.
Follow-ups it sets up
no links, so it needs no request and no base URL.
mailer.py.284 tests passing.
resolves #453
🤖 Generated with Claude Code
This is a clean move-only refactor. I've verified the two
template_folderpaths resolve to the sameapp/templatesdirectory (mailer.pyuses.parent, the router uses.parent.parent), the removeddiscord_img_urlkey is genuinely unused by any template, and both remaining importers (app/routers/mail.py:9,app/routers/v2.py:29) now pullsend_welcome_emailfromapp.mailer. One stale comment is worth a touch-up.Move-only refactor extracting the mailer (
ConnectionConfig,_send,send_welcome_email) intoapp/mailer.py, with the router andv2.pyimporting from it and dead HTTP/template artifacts left behind. The behaviour is preserved and the change is correct; the only thing I'd flag is a comment that now points at the wrong file.Nits
tests/conftest.py:84— the comment "app/routers/mail.pybuilds a fastapi-mail ConnectionConfig at module scope" is now stale: thatConnectionConfigmoved toapp/mailer.py. The reasoning (pydantic rejects aMAIL_FROMwithout an@) still holds, so the placeholder is still needed — just update the file reference so the next reader can find it.app/mailer.py:53-56— thebodydict is typeddict[str, str]on_send, which is fine, butrequest.url_for(...)returns aURLthat's explicitlystr()-wrapped here whileadmin_email/discord_invite_linkare plain strings — consistent, no action needed, just confirming thestr()calls are load-bearing for the type and the template.Nothing blocking. The removal of
EmailSchema/router/templatesfrom the mailer and thediscord_img_urlkey are all confirmed dead, and the version bump (2.22.1) follows the per-PR convention in CLAUDE.md.