Email Infrastructure

Gmail + Outlook integration with real-time sync


┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│   Gmail API      │     │  Microsoft Graph  │     │   Supabase       │
│   (OAuth 2.0)    │     │  (OAuth 2.0)      │     │   (PostgreSQL)   │
└────────┬─────────┘     └────────┬──────────┘     └────────┬─────────┘
         │                        │                         │
         ▼                        ▼                         │
┌──────────────────────────────────────────┐                │
│         Provider Abstraction Layer        │                │
│   lib/mail/google.ts  │  microsoft.ts    │                │
│         lib/mail/factory.ts              │                │
│   (auto-selects provider per account)    │                │
└────────────────────┬─────────────────────┘                │
                     │                                      │
                     ▼                                      │
┌──────────────────────────────────────────┐                │
│           Inngest Job Queue              │                │
│   syncInbox (scheduled, every 12h)       │──── upsert ───▶│
│   processWebhookEvent (on push)          │                │
│   renewWatchesAndSubscriptions           │                │
└────────────────────┬─────────────────────┘                │
                     │                                      │
                     ▼                                      ▼
┌──────────────────────────────────────────────────────────────┐
│                    Unified Inbox UI                           │
│   3-column layout │ Thread view │ Compose │ Reply │ Archive  │
│   Supabase Realtime subscriptions for instant UI updates     │
└──────────────────────────────────────────────────────────────┘

Provider Abstraction

A clean interface-based abstraction allows the platform to support multiple email providers with the same API surface. The factory pattern auto-selects the correct provider based on the connected account.

lib/mail/base.ts — Interface Contract
interface MailProvider {
  listThreads(options: ListOptions): Promise<Thread[]>
  getThread(threadId: string): Promise<ThreadDetail>
  sendMessage(params: SendParams): Promise<Message>
  replyToThread(threadId: string, params: ReplyParams): Promise<Message>
  archiveThread(threadId: string): Promise<void>
  starThread(threadId: string, starred: boolean): Promise<void>
  markAsRead(threadId: string): Promise<void>
  searchThreads(query: string): Promise<Thread[]>
}
google.ts
Gmail API
gmail.users.threads/messages, gmail.users.watch, base64url decoding
microsoft.ts
Microsoft Graph
/me/messages, /me/mailFolders, /subscriptions
factory.ts
Auto-Select
Reads account provider from DB, instantiates correct adapter

OAuth Flow

Design Decision: HostelHack uses a direct server-side OAuth flow rather than Clerk's createExternalAccount. This avoids Clerk's session re-verification requirement (403 Forbidden) and allows requesting extended mailbox scopes.
1
User clicks 'Connect Gmail'
window.location.href → /api/inbox/connect/google/start
2
Start route generates OAuth URL
Creates CSRF state token + httpOnly cookie, redirects to Google consent screen
3
User grants permissions
Google redirects to /api/inbox/connect/google/callback with auth code
4
Callback exchanges code for tokens
Access token, refresh token, and expiry stored in connected_mail_accounts table
5
Redirect to inbox
User returns to /inbox?connected=google with account ready for sync

Required Scopes

Gmail
googleapis.com/auth/gmail.modify
googleapis.com/auth/gmail.send
googleapis.com/auth/userinfo.email
Microsoft
Mail.ReadWrite
Mail.Send
User.Read

Real-time Sync

Email synchronization uses a hybrid approach: scheduled full syncs via Inngest (every 12 hours) combined with real-time delta syncs triggered by provider webhooks.

JobTriggerBehavior
syncInboxScheduled (12h) + on-demandFetch 50 threads, batch-process 10 at a time, upsert to Supabase
processWebhookEventWebhook pushDelta sync using stored cursor (historyId or deltaToken)
renewWatchesAndSubscriptionsScheduled (12h)Renew Gmail watches (7-day expiry) + Outlook subscriptions (4230 min)

Capabilities Matrix

CapabilityGmailOutlookStatus
OAuth 2.0 ConnectImplemented
List Threads (paginated)Implemented
Full Message BodiesImplemented
Send New EmailImplemented
Reply to ThreadImplemented
ArchiveImplemented
Star / FlagImplemented
Mark Read/UnreadImplemented
Attachment TrackingImplemented
Real-time PushScaffolded
Delta SyncImplemented
Token Auto-RefreshImplemented
Proposal ↔ Thread LinkImplemented

Webhook Architecture

Gmail — Pub/Sub

• Google Cloud Pub/Sub topic receives Gmail notifications

• Push subscription sends to /api/webhooks/gmail

• Webhook creates mail_sync_events row

• Inngest job performs delta sync via history.list

• Watch must be renewed every 7 days

Outlook — Graph Subscriptions

• Microsoft Graph subscription on /me/messages

• Push to /api/webhooks/microsoft-graph

• Handles validation token handshake

• Inngest job performs delta sync via deltaToken

• Subscription renewed every 4230 minutes

HostelHack Documentation · March 2026
Built with Next.js 15 · Gemini 2.0 · Supabase