Skip to content

Brand the password-reset email with a light 'Powered by Certified' style for all clients #182

Description

@holkexyz

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 emailspackages/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 emailcom.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

  • requestPasswordReset emails are styled consistently with the other
    ePDS emails (no Bluesky branding) and carry a light "Powered by Certified"
    footer.
  • Applies to all clients with no per-client configuration.
  • Plain-text alternative is updated to match (no Bluesky references).
  • (Optional) reset email previewable via /preview/emails/*.
  • (Optional, only if cheap) per-client override via client metadata, with the
    no-client-context caveat resolved or documented.

Pointers

  • packages/auth-service/src/email/templates.ts — existing branded builders
  • packages/auth-service/src/email/client-template.tsemail_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.

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions