Skip to main content

Overview

The Email Service provides comprehensive email management functionality for Macro, including Gmail integration, thread management, draft handling, and email search. It manages the full email lifecycle from inbox sync to sending. Base URL: /email Authentication: JWT authentication required. Email-specific endpoints also require a valid Gmail link via the authentication service.

Core Concepts

A “link” represents a connected email account (e.g., Gmail). Each user can have multiple links. All email operations are scoped to a specific link.

Threads

Emails are organized into threads (conversations). Each thread contains one or more messages and maintains metadata like read status and labels.

Messages

Individual email messages within threads. Messages can be:
  • Inbound (received)
  • Outbound (sent)
  • Drafts (not yet sent)
  • Scheduled (to be sent at a future time)

Threads

Get Thread Messages

GET /email/threads/{id}/messages
Retrieves all messages in a thread with pagination support.
id
string
required
Thread ID (UUID)
offset
integer
Pagination offset (default: 0)
limit
integer
Number of messages to return (default: 5, max: 100)
messages
array
Array of parsed message objects
Messages are returned in order of latest updated first. The service filters messages to only those accessible by the authenticated user’s link.
[
  {
    "id": "msg_123",
    "thread_db_id": "550e8400-e29b-41d4-a716-446655440000",
    "subject": "Product Launch",
    "from": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "to": [
      {
        "email": "[email protected]",
        "name": "Jane Smith"
      }
    ],
    "cc": [],
    "bcc": [],
    "body_text": "Message content...",
    "body_html": "<html>Message content...</html>",
    "date": "2026-03-04T10:30:00Z",
    "is_read": true,
    "has_attachments": true,
    "link_id": "link_abc123"
  }
]

List Threads

GET /email/threads
Lists email threads with filtering and pagination.
label
string
Filter by label (e.g., “INBOX”, “SENT”, “DRAFT”)
unread
boolean
Filter to unread threads only
limit
integer
Number of threads to return
cursor
string
Pagination cursor from previous response

Update Thread

PATCH /email/threads/{id}
Updates thread metadata (read status, labels, etc.).
id
string
required
Thread ID
is_read
boolean
Mark thread as read/unread
labels
array
Array of label IDs to apply

Drafts

Create Draft

POST /email/drafts
Creates a new draft message.
draft
object
required
Draft message object
draft.subject
string
Email subject
draft.to
array
required
Array of recipient email addresses
draft.cc
array
CC recipients
draft.bcc
array
BCC recipients
draft.body_text
string
Plain text body
draft.body_html
string
Base64-encoded HTML body
draft.thread_db_id
string
Thread ID if replying to existing thread
draft.replying_to_id
string
Message ID being replied to
send_time
datetime
Schedule send time (for scheduled emails)
draft
object
Created draft with generated ID
The HTML body must be Base64-encoded (URL-safe, no padding) before sending.
{
  "draft": {
    "subject": "Follow-up on Meeting",
    "to": [
      {
        "email": "[email protected]",
        "name": "Colleague Name"
      }
    ],
    "body_text": "Hi, just following up...",
    "body_html": "PGh0bWw+SGksIGp1c3QgZm9sbG93aW5nIHVwLi4uPC9odG1sPg=="
  }
}

Update Draft

PATCH /email/drafts/{id}
Updates an existing draft.
id
string
required
Draft ID

Delete Draft

DELETE /email/drafts/{id}
Deletes a draft message.

Send Draft

POST /email/drafts/{id}/send
Sends a draft immediately.

Add Attachment to Draft

POST /email/drafts/{id}/attachments
Adds an attachment to a draft.
id
string
required
Draft ID
document_id
string
required
Document ID to attach (from document storage service)

Remove Attachment from Draft

DELETE /email/drafts/{id}/attachments/{attachment_id}
Removes an attachment from a draft.

Messages

Get Message

GET /email/messages/{id}
Retrieves a single message by ID.
id
string
required
Message ID

Send Message

POST /email/messages/send
Sends a new message immediately (bypasses draft creation).
message
object
required
Message object (same structure as draft)

Attachments

Get Attachment

GET /email/attachments/{id}
Downloads an email attachment.
id
string
required
Attachment ID
url
string
Signed URL to download the attachment
filename
string
Original filename
size_bytes
integer
File size in bytes
mime_type
string
MIME type of the attachment

Get Attachment Document ID

GET /email/attachments/{id}/document_id
Returns the document storage service document ID for an attachment (if it has been imported).

Labels

List Labels

GET /email/labels
Lists all labels/folders for the connected email account.
labels
array
Array of label objects

Create Label

POST /email/labels
Creates a new label.
name
string
required
Label name

Contacts

List Contacts

GET /email/contacts
Retrieves email contacts with search and pagination.
Search query for contact name or email
limit
integer
Number of contacts to return
contacts
array
Array of contact objects with email, name, and interaction count

Backfill & Sync

Start Backfill

POST /email/backfill
Starts a backfill operation to sync historical emails from Gmail.
start_date
datetime
Start date for backfill (defaults to account creation)
end_date
datetime
End date for backfill (defaults to now)
backfill_id
string
Unique backfill operation ID

Get Backfill Status

GET /email/backfill/{id}
Checks the status of a backfill operation.
status
string
Status: pending, in_progress, completed, failed, cancelled
progress
object
Progress information including total and processed count

Cancel Backfill

POST /email/backfill/{id}/cancel
Cancels an in-progress backfill operation.

Settings

Get Email Settings

GET /email/settings
Retrieves email account settings.

Update Email Settings

PATCH /email/settings
Updates email account settings.
signature
string
Email signature (HTML)
auto_bcc
string
Email address to automatically BCC on all sent messages

Initialize Email

Initialize Email Account

POST /email/init
Initializes email service for a newly linked Gmail account. This endpoint:
  • Validates the Gmail token
  • Creates initial database records
  • Starts the inbox sync
This endpoint requires a valid Gmail access token in the request headers.

Error Codes

Common Errors

  • 400 - Bad Request (validation error)
  • 401 - Unauthorized (no valid link)
  • 403 - Forbidden (rate limit or permissions)
  • 404 - Not Found (thread/message doesn’t exist)
  • 429 - Too Many Requests (rate limited by Gmail API)
  • 500 - Internal Server Error

Service-Specific Error Codes

  • GMAIL_TOKEN_EXPIRED - Gmail access token needs refresh
  • INVALID_RECIPIENT - One or more recipient email addresses invalid
  • ATTACHMENT_TOO_LARGE - Attachment exceeds size limit
  • THREAD_NOT_ACCESSIBLE - Thread belongs to different link
  • RATE_LIMIT_EXCEEDED - Gmail API rate limit reached
  • BACKFILL_IN_PROGRESS - Cannot start new backfill while one is running
{
  "message": "Gmail access token has expired. Please re-authenticate.",
  "error_code": "GMAIL_TOKEN_EXPIRED"
}

Data Models

Thread

interface Thread {
  db_id: string;                    // UUID
  provider_id?: string;             // Gmail thread ID
  link_id: string;                  // Connected account ID
  inbox_visible: boolean;
  is_read: boolean;
  latest_inbound_message_ts?: string;
  latest_outbound_message_ts?: string;
  created_at: string;
  updated_at: string;
  messages: Message[];
}

Message

interface Message {
  id: string;
  thread_db_id: string;
  subject?: string;
  from: EmailAddress;
  to: EmailAddress[];
  cc: EmailAddress[];
  bcc: EmailAddress[];
  body_text?: string;
  body_html?: string;
  date: string;
  is_read: boolean;
  has_attachments: boolean;
  link_id: string;
  provider_id?: string;             // Gmail message ID
}

interface EmailAddress {
  email: string;
  name?: string;
}

Draft

interface MessageToSend {
  id?: string;
  subject?: string;
  to: EmailAddress[];
  cc?: EmailAddress[];
  bcc?: EmailAddress[];
  body_text?: string;
  body_html?: string;                // Base64-encoded
  thread_db_id?: string;
  replying_to_id?: string;
  link_id: string;
}

Contact

interface Contact {
  email: string;
  name?: string;
  interaction_count: number;
  last_interaction: string;
}

Build docs developers (and LLMs) love