Skip to content

Email Service

Cora uses two distinct email channels:

ChannelProviderPurpose
Campaign emailsGmail API (OAuth)Outbound sales sequences — sent via connected sender accounts
Transactional emailsResendAuth emails (verification, password reset, 2FA)

Campaign Emails — Gmail OAuth

Campaign emails are sent through Gmail accounts connected by the brand. This provides:

  • High deliverability (uses the sender's real Gmail account)
  • Thread continuity (replies land in the same Gmail thread)
  • Warmup management (gradual daily send limit increases)

Sender Account Flow

Warmup

New Gmail accounts start with a low daily send limit. The worker cron resets sendsToday = 0 each midnight UTC and progressively increases dailyLimit based on warmup schedules. Accounts in warmup are skipped if they've reached their current limit; the worker tries up to 3 accounts before rescheduling.

Reply Detection

Inbound Gmail replies are detected via webhook callbacks. When a reply is received:

  1. CampaignLeads.hasReplied is set to true
  2. All pending step jobs for that contact are skipped
  3. A Conversation record captures the thread for the inbox view

Transactional Emails — Resend

Auth-related emails are sent via Resend using the RESEND_API_KEY env var. Templates are defined in packages/auth/src/emails.ts:

  • Email address verification on sign-up
  • Magic link / password reset
  • Two-factor auth codes

Sender Account Data Model

The SenderAccount model (stored in MongoDB) tracks per-account state:

FieldPurpose
connectionStatusVERIFIED / BROKEN / PENDING
isActiveWhether the account can be used for sending
dailyLimitCurrent max sends per day (increases with warmup)
sendsTodayCounter reset each midnight
lastSendAtTimestamp of last outbound message
accessToken / refreshTokenGmail OAuth credentials