Shank Email Templates
Shank is not a runtime service. It is a build-time React Email project that compiles JSX templates to static HTML and writes the result into sirloin’s embedded template directory. There is no network surface, no endpoints, no public API.
The “API” of shank is the set of HTML files it produces and the placeholder
tokens those files contain. Sirloin’s internal/pkg/emails package treats
these as plain string templates and substitutes {{TOKEN}} placeholders at
send time (see apps/sirloin/internal/pkg/emails/client.go).
Source location
Section titled “Source location”- React Email project:
apps/shank/react-templates/ - Templates:
apps/shank/react-templates/emails/*.tsx - Export target (committed):
apps/sirloin/internal/pkg/emails/templates/*.html
The export path is hardcoded in apps/shank/react-templates/package.json:
"export": "email export --outDir='../../sirloin/internal/pkg/emails/templates'"Exported templates
Section titled “Exported templates”| Source TSX | Exported HTML | Sirloin sender |
|---|---|---|
emails/manual-review-custom-vi-approved.tsx |
templates/manual-review-custom-vi-approved.html |
Client.SendManualReviewCustomVIApproved |
emails/manual-review-custom-vi-rejected.tsx |
templates/manual-review-custom-vi-rejected.html |
Client.SendManualReviewCustomVIRejected |
emails/manual-review-ri-approved.tsx |
templates/manual-review-ri-approved.html |
Client.SendManualReviewRIApproved |
emails/manual-review-ri-rejected.tsx |
templates/manual-review-ri-rejected.html |
Client.SendManualReviewRIRejected |
Placeholders: {{CHARACTER_NAME}}, {{CHARACTER_ID}} and {{REVIEW_RESULTS}}
(check one template with grep -oE '\{\{[A-Z_]+\}\}' apps/sirloin/internal/pkg/emails/templates/<name>.html). Caller:
apps/sirloin/internal/app/services/strip/striplikenessreviewemail.go.
The training-done and training-failed templates were retired in
ENGINE-3; sirloin no longer sends a training-completion email.
How sirloin consumes the templates
Section titled “How sirloin consumes the templates”apps/sirloin/internal/pkg/emails/client.go embeds the template directory
at compile time:
//go:embed templatesvar emailTemplates embed.FSOn NewClient, it reads every required template from the embedded
directory into in-memory strings. Each Send* method does straight
strings.ReplaceAll substitution on the {{TOKEN}} placeholders, then
sends via SMTP+TLS using credentials passed to NewClient.
This means:
- Templates are part of the sirloin binary after
pnpm export+go build. - Shank changes are not deployed independently — sirloin must be rebuilt and redeployed to pick them up.
- New placeholders require two coordinated changes: the template (shank) and the substitution call (sirloin).
Adding a new template
Section titled “Adding a new template”- Add
apps/shank/react-templates/emails/<name>.tsx. - Use
{{TOKEN}}placeholders for any dynamic content. Tokens are uppercase snake-case by convention ({{CHARACTER_NAME}},{{CHARACTER_ID}}). - Run
pnpm exportfromapps/shank/react-templates/. - Add a loader branch in
Client.NewClientfor the new HTML file. - Add a
Send<Name>method that does thestrings.ReplaceAllsubstitution and callsc.send. - Wire the caller (typically a worker in
apps/sirloin/internal/app/worker/). - Commit both the source TSX and the exported HTML.
See shank-runbook.md for the full release flow.