generalbots/botbook/src/08-rest-api-tools/email-api.md
Rodrigo Rodriguez (Pragmatismo) 037db5c381 feat: Major workspace reorganization and documentation update
- Add comprehensive documentation in botbook/ with 12 chapters
- Add botapp/ Tauri desktop application
- Add botdevice/ IoT device support
- Add botlib/ shared library crate
- Add botmodels/ Python ML models service
- Add botplugin/ browser extension
- Add botserver/ reorganized server code
- Add bottemplates/ bot templates
- Add bottest/ integration tests
- Add botui/ web UI server
- Add CI/CD workflows in .forgejo/workflows/
- Add AGENTS.md and PROD.md documentation
- Add dependency management scripts (DEPENDENCIES.sh/ps1)
- Remove legacy src/ structure and migrations
- Clean up temporary and backup files
2026-04-19 08:14:25 -03:00

12 KiB

Email API

The Email API provides endpoints for email operations including sending, receiving, and managing email accounts through the Stalwart mail server integration.

Overview

Email functionality in General Bots is available through:

  1. REST API - Documented in this chapter
  2. BASIC Keywords - SEND MAIL for scripts
  3. Email Module - Background processing and IMAP/SMTP integration

Endpoints

Send Email

POST /api/email/send

Send an email message.

Request:

{
  "to": ["recipient@example.com"],
  "cc": ["cc@example.com"],
  "bcc": [],
  "subject": "Meeting Tomorrow",
  "body": "Hi, just a reminder about our meeting.",
  "body_type": "text",
  "attachments": []
}

Response:

{
  "message_id": "msg-abc123",
  "status": "sent",
  "timestamp": "2024-01-15T10:30:00Z"
}

Body Types:

  • text - Plain text
  • html - HTML formatted

List Emails

GET /api/email/inbox

Retrieve inbox messages.

Query Parameters:

  • folder - Folder name (default: INBOX)
  • limit - Number of messages (default: 50)
  • offset - Pagination offset
  • unread - Filter unread only (boolean)
  • since - Messages since date (ISO 8601)

Response:

{
  "messages": [
    {
      "id": "email-001",
      "from": "sender@example.com",
      "subject": "Hello",
      "preview": "Just wanted to say hi...",
      "date": "2024-01-15T09:00:00Z",
      "read": false,
      "has_attachments": false
    }
  ],
  "total": 142,
  "unread_count": 5
}

Get Email

GET /api/email/:id

Get specific email details.

Response:

{
  "id": "email-001",
  "from": {
    "name": "John Doe",
    "email": "john@example.com"
  },
  "to": [
    {
      "name": "You",
      "email": "you@example.com"
    }
  ],
  "cc": [],
  "subject": "Meeting Notes",
  "body": "Here are the notes from today's meeting...",
  "body_html": "<p>Here are the notes from today's meeting...</p>",
  "date": "2024-01-15T09:00:00Z",
  "read": true,
  "attachments": [
    {
      "id": "att-001",
      "filename": "notes.pdf",
      "size": 102400,
      "content_type": "application/pdf"
    }
  ]
}

Delete Email

DELETE /api/email/:id

Delete an email message.

Response:

{
  "status": "deleted",
  "message_id": "email-001"
}

Get Attachment

GET /api/email/:id/attachments/:attachment_id

Download an email attachment.

Response: Binary file with appropriate Content-Type header.

Mark as Read

PUT /api/email/:id/read

Mark email as read.

Request:

{
  "read": true
}

Move Email

PUT /api/email/:id/move

Move email to a different folder.

Request:

{
  "folder": "Archive"
}

List Folders

GET /api/email/folders

List available email folders.

Response:

{
  "folders": [
    {
      "name": "INBOX",
      "path": "INBOX",
      "unread_count": 5,
      "total_count": 142
    },
    {
      "name": "Sent",
      "path": "Sent",
      "unread_count": 0,
      "total_count": 89
    },
    {
      "name": "Drafts",
      "path": "Drafts",
      "unread_count": 0,
      "total_count": 3
    }
  ]
}

Create Draft

POST /api/email/drafts

Create an email draft.

Request:

{
  "to": ["recipient@example.com"],
  "subject": "Draft subject",
  "body": "Draft content..."
}

Response:

{
  "draft_id": "draft-001",
  "status": "saved"
}

Send Draft

POST /api/email/drafts/:id/send

Send a previously saved draft.

Response:

{
  "message_id": "msg-abc123",
  "status": "sent"
}

Email Accounts

List Accounts

GET /api/email/accounts

List configured email accounts.

Response:

{
  "accounts": [
    {
      "id": "account-001",
      "email": "user@example.com",
      "provider": "stalwart",
      "status": "connected"
    }
  ]
}

Add Account

POST /api/email/accounts

Add a new email account.

Request:

{
  "email": "user@example.com",
  "imap_server": "imap.example.com",
  "imap_port": 993,
  "smtp_server": "smtp.example.com",
  "smtp_port": 587,
  "username": "user@example.com",
  "password": "app-specific-password"
}

Response:

{
  "account_id": "account-002",
  "status": "connected",
  "message": "Account added successfully"
}

BASIC Integration

Use email in your BASIC scripts:

' Simple email
SEND MAIL "recipient@example.com", "Subject", "Body"

' With variables
TALK "Who should I email?"
recipient = HEAR

TALK "What's the subject?"
subject = HEAR

TALK "What's the message?"
body = HEAR

SEND MAIL recipient, subject, body
TALK "Email sent!"

Configuration

Configure email in config.csv:

key,value
smtp-server,smtp.gmail.com
smtp-port,587
imap-server,imap.gmail.com
imap-port,993
email-username,your-email@gmail.com
email-password,your-app-password
email-from,Your Name <your-email@gmail.com>

Gmail Configuration:

  • Use App Passwords (not your main password)
  • Enable IMAP in Gmail settings
  • Allow less secure apps or use OAuth

Stalwart Mail Server

When using the built-in Stalwart mail server:

Automatic Configuration:

  • Server runs on standard ports (25, 993, 587)
  • Accounts created through Zitadel integration
  • TLS certificates auto-managed

Manual Configuration:

key,value
stalwart-enabled,true
stalwart-domain,mail.yourdomain.com
stalwart-admin-password,secure-password

Error Handling

Status Code Error Description
400 invalid_recipient Invalid email address
401 unauthorized Authentication required
403 forbidden No access to mailbox
404 not_found Email not found
422 send_failed SMTP delivery failed
503 service_unavailable Mail server offline

Rate Limits

Endpoint Limit
Send 100/hour per user
Inbox 300/hour per user
Attachments 50/hour per user

Email Read Tracking

General Bots supports email read tracking via an invisible 1x1 pixel embedded in HTML emails. When enabled, you can track when recipients open your emails.

Configuration

Enable tracking in config.csv:

name,value
email-read-pixel,true
server-url,https://yourdomain.com

How It Works

  1. When sending an HTML email, a tracking pixel is automatically injected
  2. When the recipient opens the email, their email client loads the pixel
  3. The server records the open event with timestamp and metadata
  4. You can query the tracking status via API or view in the Suite UI

Tracking Endpoints

Serve Tracking Pixel

GET /api/email/tracking/pixel/:tracking_id

This endpoint is called automatically by email clients when loading the tracking pixel. It returns a 1x1 transparent GIF and records the read event.

Response: Binary GIF image (1x1 pixel)

Headers Set:

  • Content-Type: image/gif
  • Cache-Control: no-store, no-cache, must-revalidate, max-age=0

Get Tracking Status

GET /api/email/tracking/status/:tracking_id

Get the read status for a specific sent email.

Response:

{
  "success": true,
  "data": {
    "tracking_id": "550e8400-e29b-41d4-a716-446655440000",
    "to_email": "recipient@example.com",
    "subject": "Meeting Tomorrow",
    "sent_at": "2024-01-15T10:30:00Z",
    "is_read": true,
    "read_at": "2024-01-15T14:22:00Z",
    "read_count": 3
  }
}

List Tracked Emails

GET /api/email/tracking/list

List all sent emails with their tracking status.

Query Parameters:

  • account_id - Filter by email account (optional)
  • limit - Number of results (default: 50)
  • offset - Pagination offset (default: 0)
  • filter - Filter by status: all, read, unread (default: all)

Response:

{
  "success": true,
  "data": [
    {
      "tracking_id": "550e8400-e29b-41d4-a716-446655440000",
      "to_email": "recipient@example.com",
      "subject": "Meeting Tomorrow",
      "sent_at": "2024-01-15T10:30:00Z",
      "is_read": true,
      "read_at": "2024-01-15T14:22:00Z",
      "read_count": 3
    },
    {
      "tracking_id": "661e8400-e29b-41d4-a716-446655440001",
      "to_email": "another@example.com",
      "subject": "Project Update",
      "sent_at": "2024-01-15T11:00:00Z",
      "is_read": false,
      "read_at": null,
      "read_count": 0
    }
  ]
}

Get Tracking Statistics

GET /api/email/tracking/stats

Get aggregate statistics for email tracking.

Response:

{
  "success": true,
  "data": {
    "total_sent": 150,
    "total_read": 98,
    "read_rate": 65.33,
    "avg_time_to_read_hours": 4.5
  }
}

Tracking Data Stored

For each tracked email, the following data is recorded:

Field Description
tracking_id Unique ID embedded in the pixel URL
to_email Recipient email address
subject Email subject line
sent_at Timestamp when email was sent
is_read Whether email has been opened
read_at Timestamp of first open
read_count Number of times opened
first_read_ip IP address of first open
last_read_ip IP address of most recent open
user_agent Browser/client user agent string

Privacy Considerations

  • Email tracking should be used responsibly
  • Consider disclosing tracking in your email footer
  • Some email clients block tracking pixels by default
  • Users may have images disabled, preventing tracking
  • GDPR/LGPD may require consent for tracking

Suite UI Integration

The Suite email interface shows tracking status:

  • 📊 Tracking folder shows all tracked emails
  • Green checkmarks (✓✓) indicate opened emails
  • Gray checkmarks indicate sent but unread
  • Hover over emails to see open timestamp
  • Statistics panel shows open rates

Security Notes

  1. Never hardcode credentials - Use config.csv
  2. Use App Passwords - Not main account passwords
  3. Enable TLS - Always use encrypted connections
  4. Audit sending - Log all outbound emails

Database Schema

-- user_email_accounts
CREATE TABLE user_email_accounts (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id),
    email TEXT NOT NULL,
    imap_server TEXT,
    smtp_server TEXT,
    encrypted_password TEXT,
    created_at TIMESTAMPTZ
);

-- email_drafts
CREATE TABLE email_drafts (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id),
    recipients JSONB,
    subject TEXT,
    body TEXT,
    attachments JSONB,
    created_at TIMESTAMPTZ,
    updated_at TIMESTAMPTZ
);

Database Schema

-- user_email_accounts
CREATE TABLE user_email_accounts (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id),
    email TEXT NOT NULL,
    imap_server TEXT,
    smtp_server TEXT,
    encrypted_password TEXT,
    created_at TIMESTAMPTZ
);

-- email_drafts
CREATE TABLE email_drafts (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id),
    recipients JSONB,
    subject TEXT,
    body TEXT,
    attachments JSONB,
    created_at TIMESTAMPTZ,
    updated_at TIMESTAMPTZ
);

-- sent_email_tracking (for read receipts)
CREATE TABLE sent_email_tracking (
    id UUID PRIMARY KEY,
    tracking_id UUID NOT NULL UNIQUE,
    bot_id UUID NOT NULL,
    account_id UUID NOT NULL,
    from_email VARCHAR(255) NOT NULL,
    to_email VARCHAR(255) NOT NULL,
    cc TEXT,
    bcc TEXT,
    subject TEXT NOT NULL,
    sent_at TIMESTAMPTZ NOT NULL,
    is_read BOOLEAN NOT NULL DEFAULT FALSE,
    read_at TIMESTAMPTZ,
    read_count INTEGER NOT NULL DEFAULT 0,
    first_read_ip VARCHAR(45),
    last_read_ip VARCHAR(45),
    user_agent TEXT,
    created_at TIMESTAMPTZ NOT NULL,
    updated_at TIMESTAMPTZ NOT NULL
);

See Also