Skip to content

Add kit.email: one port, one adapter, no vendor in the caller #9

Description

@crypto-a

Services are starting to send mail. api needs invitation emails now, and the obvious
shape, a typed gateway per service over a vendor SDK, gives every service its own timeout,
its own retry opinion and its own coupling to Resend.

This is the kit.clients case rather than the database-helpers case. It is not an
abstraction over a domain, it is delivery policy plus a provider swap, and both are wrong
in the same way in every service that writes them alone. The README's rule ("code moves in
on its third copy") is about domain abstractions; the carve-out already written down for
kit.clients is the precedent, and the boundary that keeps it honest is that templates,
rendering and "who gets which email" stay in the service.

Proposed surface:

  • EmailMessage: recipients, subject, text body, html body, sender, reply-to. Nothing else,
    because everything else is where providers differ.
  • Delivery: what the provider said it accepted.
  • Emailer: a Protocol, so adapters never import it and services fake it structurally.
  • ResendEmailer: the one adapter, built on a kit.clients.ServiceClient, so it inherits
    the deadline, the jittered backoff, the breaker, trace context and the /readyz line
    rather than reimplementing them.

No new dependency: Resend is spoken to over the httpx that is already here, never the
vendor SDK.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions