Skip to main content
apps/mail is the standalone Tuturuuu mailbox app. It runs on https://mail.tuturuuu.com in production and port 7820 locally, delegates auth to apps/web, and only admits exact @tuturuuu.com accounts. Addresses such as @xwf.tuturuuu.com are intentionally denied.

Architecture

  • apps/mail owns the mailbox UI and proxies /api/* to apps/web.
  • apps/web owns all protected mail APIs under /api/v1/workspaces/:wsId/mail/*.
  • The mailbox mirror is stored in private.mail_* tables and is service-role only. App pages and route handlers must authorize exact-domain users and mailbox membership before returning data.
  • Outbound messages use @tuturuuu/email-service with the selected mailbox address as the source.
  • Inbound messages use SES Email Receiving with S3 raw-message storage and SNS notifications. The webhook stores an idempotent inbound job, fetches raw MIME from S3, mirrors sanitized bodies and attachment metadata, and quarantines unknown recipients.
Mail consumes /verify-token in the proxy before centralized auth handling so local Portless handoffs set cookies on mail.tuturuuu.localhost. The app keeps token refresh same-origin through /api/auth/refresh-app-session; a valid refresh cookie should rotate the Mail-local and Web-issued app-session cookies without sending the browser back through apps/web login.

SES Receiving Setup

Do not change DNS from code or migrations. The current public MX for tuturuuu.com is Google-routed, so real @tuturuuu.com receiving requires an explicit staged MX cutover or a pilot subdomain first.
  1. Verify the domain or pilot subdomain in the SES receiving region.
  2. Create an S3 bucket for raw MIME objects.
  3. Create an SNS topic for receipt notifications and subscribe the web webhook: POST /api/v1/webhooks/mail/ses.
  4. Create an SES receipt rule that stores raw MIME in S3 and publishes the SNS notification.
  5. Configure MAIL_SES_INBOUND_TOPIC_ARN, MAIL_SES_INBOUND_BUCKET, MAIL_SES_INBOUND_KEY_PREFIX, and MAIL_SES_REGION.
  6. Only after validation, stage the MX/DNS change outside the app repository.
For local SNS fixture tests, set MAIL_SES_SNS_SIGNATURE_VERIFICATION=disabled. Do not use that setting in production.

Operations

  • Run bun sb:up locally after mail schema changes, then bun sb:typegen.
  • Keep new mail route access checks in apps/web; do not add direct client Supabase reads in apps/mail.
  • Use packages/internal-api/src/mail.ts for client helpers and TanStack Query in the app UI.
  • Unknown inbound recipients are retained as quarantined jobs for administrator review instead of being delivered to a user inbox.
  • Keep generated public assets such as /manifest.webmanifest, /sw.js, and Serwist worker files out of the auth proxy matcher. Redirecting those files to central Web login breaks standalone Mail startup and PWA registration.
  • Keep apps/mail/src/proxy.ts config.matcher entries as inline string literals. Next.js statically parses proxy matcher config during Vercel builds and rejects imported constants even when they resolve to strings.

CI and deployment

Mail has dedicated Vercel workflows:
  • .github/workflows/vercel-preview-mail.yaml
  • .github/workflows/vercel-production-mail.yaml
Both workflows are registered in tuturuuu.ts and use the shared ci-check.yml switchboard. They require environment-scoped Vercel credentials plus VERCEL_MAIL_PROJECT_ID; production Supabase and SES values should live in the Vercel project environment rather than GitHub Actions. The preview workflow builds and deploys prebuilt artifacts through Vercel CLI. The production workflow also uses workflow concurrency so stale production runs are canceled instead of deploying after a newer production commit is pushed. Deployment credentials must stay environment-scoped in GitHub Actions. The preview job is bound to the vercel-preview-mail GitHub Environment, and the production job is bound to vercel-production-mail. Store VERCEL_TOKEN, VERCEL_ORG_ID, and VERCEL_MAIL_PROJECT_ID in those environments instead of repository-wide or organization-wide secrets. Do not add TURBO_TOKEN, TURBO_TEAM, production Supabase service keys, or SES credentials to workflow-level env; Mail deploys should rely on Vercel project environment variables pulled by vercel pull. Manual production dispatch is only valid from refs/heads/production. apps/mail/vercel.json disables Vercel Git deployments and GitHub integration so preview and production deploys only happen through the CI workflows.