# Resend Transactional Email

## Objective

Send application email through Resend with verified domains and tracked delivery.

A Resend delivery path with domain verification gating production sends, controlled attachments, and recorded delivery events.

## Before You Begin

This feature is being added to an application that already exists and already
works. Do not scaffold a new project, and do not assume a blank slate.

Inspect the codebase first and establish:

- The existing application structure and where code of this kind already lives.
- The framework and version in use.
- The existing design system — colours, spacing, typography, and component conventions.
- Existing UI components you can reuse instead of writing new ones.
- The existing database structure, if this feature needs to persist anything.
- The existing authentication and authorization system, if this feature is user-scoped.
- Dependencies already installed, so you don't add a library that duplicates one.
- The existing test setup and conventions.

Only start writing code once you understand the above. If the application
already implements part of this feature, extend it rather than replacing it.

## Implementation Instructions

1. Put Resend behind the app's existing mail layer as one adapter. This entry is an alternative to the other transactional email integrations rather than a companion to them; the mail layer, template contract, and suppression handling stay the same whichever adapter is in place.
2. Gate production delivery on a verified sending domain. Until verification is confirmed, keep the app in a mode that redirects or suppresses delivery rather than sending from an unverified address into spam folders.
3. Send from the app's background-job system, keyed on a stable per-message identifier, and store the provider's identifier on the record as soon as it is returned.
4. Resolve attachments server-side from the app's own storage, enforce a size ceiling before the job is queued, and re-check that the recipient is entitled to the attached file at send time.
5. Consume delivery and bounce events on a verified endpoint and maintain suppression state that every future send checks before queueing.

## UI and UX Requirements

Match the application's existing design system exactly. Reuse its components,
spacing, and typography. This feature should look like it was always there.

## Responsive Requirements

Works on mobile, tablet, and desktop. Touch targets are large enough to hit on a
phone, and nothing overflows horizontally at 320px.

## Accessibility Requirements

- Fully keyboard navigable.
- Correct semantic elements and ARIA roles.
- Visible focus states.
- Meets WCAG AA contrast.
- Dynamic changes are announced to screen readers.
- Respects prefers-reduced-motion.

## Edge Cases

- Sending from an unverified domain lands mail in spam and damages the domain's reputation. Treat verification as a precondition for production delivery, and show its state clearly to an operator rather than letting it fail quietly.
- Attachments have a size ceiling and are resolved from files the app controls. Check the size before queueing so an oversized file fails visibly at composition, and re-check access at send time so a file the recipient has lost permission to is not attached anyway.
- Asynchronous send jobs retried after a timeout will otherwise deliver the same email twice. Key each send on a stable identifier and reconcile the retry against the existing record.
- Provider identifiers and webhook events are what make a delivery question answerable. Store the identifier on the message record and process events on a verified, idempotent endpoint, since events can be replayed and can arrive out of order.
- Development and staging must never reach real recipients. Default those environments to suppressing delivery or redirecting every recipient to a fixed internal address, and do not rely on a data set being fake.
- Transactional email must not be conditioned on marketing consent, and marketing email must not be smuggled through this path to reach people who unsubscribed.
- Credentials and full message bodies must be absent from logs and error reports, because a captured reset link or one-time code is a live credential.
- When the provider is unavailable, the triggering action must still succeed, the message must stay queued, and the app must tell the user the email is on its way rather than claiming delivery.

## Testing

Exercise the feature end to end in the running application. Cover every edge case
above, then run the existing test suite and confirm nothing regressed.

## Acceptance Criteria

- [ ] Production delivery is blocked until the sending domain is verified, and verification state is visible to operators.
- [ ] Attachments are resolved server-side, size-checked before queueing, and access-checked at send time.
- [ ] Every message record carries the provider identifier.
- [ ] Delivery and bounce webhooks are authenticated, idempotent, and update suppression state.
- [ ] Retried jobs never send the same email twice.
- [ ] Non-production environments cannot deliver to real recipients.
- [ ] No log or error report contains credentials or full message bodies.
- [ ] The feature matches the existing design system.
- [ ] No existing functionality is broken.

## Adaptation Rules

- Match the existing design system. Do not introduce a new colour palette,
  spacing scale, or component library.
- Reuse existing components and utilities wherever they fit.
- Follow the naming, file layout, and code style already present.
- Do not upgrade, replace, or remove existing dependencies to make this
  feature fit. Adapt the feature to the app, not the app to the feature.
- Do not break existing functionality. If a change is genuinely required in
  existing code, make the smallest one that works and say so.
- If something in these instructions conflicts with how the application is
  built, follow the application and explain the deviation.

## Final Verification

Before you report the work as done:

1. Re-read the acceptance criteria above and check each one against what you
   actually built.
2. Run the application and exercise the feature end to end.
3. Run the existing test suite and confirm you have broken nothing.
4. Check the feature on mobile, tablet, and desktop widths.
5. Check keyboard navigation and focus handling.
6. Summarize what changed: files added, files modified, and anything you
   deliberately did differently because of how this application is built.

If any acceptance criterion is unmet, fix it before reporting completion.
