Summary
The password-reset email (com.atproto.server.requestPasswordReset) is the only
account email that still ships with the upstream @atproto/pds default styling
(Bluesky-branded). ePDS has re-styled its own auth-service emails, but the
reset email falls through to the inherited pds-core mailer template and so
arrives looking like stock Bluesky.
Request: give the reset email a light, neutral "Powered by Certified" style
that applies to all clients by default, consistent with the existing
auth-service email templates. Optionally — only if it's cheap — allow a client
to override it via client metadata, the way email_template_uri already brands
the OTP email.
Current behaviour
Two separate email systems exist today:
- auth-service emails —
packages/auth-service/src/email/templates.ts
(buildSignInCodeEmail, buildWelcomeCodeEmail,
buildBackupEmailVerificationEmail). These are ePDS-styled, and the OTP one
is additionally client-brandable via email_template_uri
(packages/auth-service/src/email/client-template.ts).
- pds-core reset email —
com.atproto.server.requestPasswordReset is served
by pds-core (the forked atproto PDS). packages/pds-core contains no
mailer/email/template files, and auth-service has no password-reset
builder, so the email is produced by the upstream @atproto/pds ServerMailer
resetPassword template — i.e. the Bluesky default.
A downstream client (Certified) confirmed the reset email arrives Bluesky-styled
while the OTP email is correctly Certified-branded.
Why it matters
For OTP-first clients the reset email is low-frequency (it only appears when a
user sets/changes a password for app-password / ATProto-client use), but it is
the one place the experience visibly breaks brand consistency and references
Bluesky, which is confusing for users of a non-Bluesky PDS.
Proposed change (primary): brand the default reset email
Override the pds-core resetPassword mailer template with a light, neutral
ePDS-styled email that matches the look of the auth-service templates
(system-font stack, generous spacing, the existing #0f1828 accent, a hairline
divider) and ends with a small "Powered by Certified" footer. No per-client
configuration — every client on the PDS gets the consistent, operator-branded
reset email out of the box.
Suggested approach (whichever fits the fork's structure best):
- supply a custom
resetPassword template to the pds-core ServerMailer, or
- add a
buildPasswordResetEmail(...) builder to
packages/auth-service/src/email/templates.ts and route the reset email
through the same sender as the other ePDS emails, keeping all email styling in
one place.
Keeping it in templates.ts would also let it show up in the existing
/preview/emails/* routes for easy iteration.
Optional: per-client styling via client metadata
If it turns out to be easy, extend the existing client-metadata email-template
machinery (client-template.ts, email_template_uri) to also cover the reset
email — e.g. a reset_password_email_template_uri field, reusing the same
SSRF-hardened fetch, allowlist, caching, and {{...}} substitution.
Caveat that likely makes this hard: requestPasswordReset is initiated with
only an account identifier and carries no OAuth client_id, so the PDS has
no client context at send time to decide whose template to use. Unless the reset
is triggered through a client-aware path, per-client branding may not be
resolvable — which is exactly why the operator-level "Powered by Certified"
default above is the primary ask. Treat this section as nice-to-have only.
Acceptance criteria
Pointers
packages/auth-service/src/email/templates.ts — existing branded builders
packages/auth-service/src/email/client-template.ts — email_template_uri machinery
packages/auth-service/src/routes/preview-emails.ts — email preview routes
packages/pds-core — currently no mailer override (inherits @atproto/pds)
Filed from the Certified app integration.
Summary
The password-reset email (
com.atproto.server.requestPasswordReset) is the onlyaccount email that still ships with the upstream
@atproto/pdsdefault styling(Bluesky-branded). ePDS has re-styled its own auth-service emails, but the
reset email falls through to the inherited pds-core mailer template and so
arrives looking like stock Bluesky.
Request: give the reset email a light, neutral "Powered by Certified" style
that applies to all clients by default, consistent with the existing
auth-service email templates. Optionally — only if it's cheap — allow a client
to override it via client metadata, the way
email_template_urialready brandsthe OTP email.
Current behaviour
Two separate email systems exist today:
packages/auth-service/src/email/templates.ts(
buildSignInCodeEmail,buildWelcomeCodeEmail,buildBackupEmailVerificationEmail). These are ePDS-styled, and the OTP oneis additionally client-brandable via
email_template_uri(
packages/auth-service/src/email/client-template.ts).com.atproto.server.requestPasswordResetis servedby pds-core (the forked atproto PDS).
packages/pds-corecontains nomailer/email/template files, and auth-service has no password-reset
builder, so the email is produced by the upstream
@atproto/pdsServerMailerresetPasswordtemplate — i.e. the Bluesky default.A downstream client (Certified) confirmed the reset email arrives Bluesky-styled
while the OTP email is correctly Certified-branded.
Why it matters
For OTP-first clients the reset email is low-frequency (it only appears when a
user sets/changes a password for app-password / ATProto-client use), but it is
the one place the experience visibly breaks brand consistency and references
Bluesky, which is confusing for users of a non-Bluesky PDS.
Proposed change (primary): brand the default reset email
Override the pds-core
resetPasswordmailer template with a light, neutralePDS-styled email that matches the look of the auth-service templates
(system-font stack, generous spacing, the existing
#0f1828accent, a hairlinedivider) and ends with a small "Powered by Certified" footer. No per-client
configuration — every client on the PDS gets the consistent, operator-branded
reset email out of the box.
Suggested approach (whichever fits the fork's structure best):
resetPasswordtemplate to the pds-coreServerMailer, orbuildPasswordResetEmail(...)builder topackages/auth-service/src/email/templates.tsand route the reset emailthrough the same sender as the other ePDS emails, keeping all email styling in
one place.
Keeping it in
templates.tswould also let it show up in the existing/preview/emails/*routes for easy iteration.Optional: per-client styling via client metadata
If it turns out to be easy, extend the existing client-metadata email-template
machinery (
client-template.ts,email_template_uri) to also cover the resetemail — e.g. a
reset_password_email_template_urifield, reusing the sameSSRF-hardened fetch, allowlist, caching, and
{{...}}substitution.Caveat that likely makes this hard:
requestPasswordResetis initiated withonly an account identifier and carries no OAuth
client_id, so the PDS hasno client context at send time to decide whose template to use. Unless the reset
is triggered through a client-aware path, per-client branding may not be
resolvable — which is exactly why the operator-level "Powered by Certified"
default above is the primary ask. Treat this section as nice-to-have only.
Acceptance criteria
requestPasswordResetemails are styled consistently with the otherePDS emails (no Bluesky branding) and carry a light "Powered by Certified"
footer.
/preview/emails/*.no-client-context caveat resolved or documented.
Pointers
packages/auth-service/src/email/templates.ts— existing branded builderspackages/auth-service/src/email/client-template.ts—email_template_urimachinerypackages/auth-service/src/routes/preview-emails.ts— email preview routespackages/pds-core— currently no mailer override (inherits@atproto/pds)Filed from the Certified app integration.