Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 CodeErrorDescription
400invalid_recipientInvalid email address
401unauthorizedAuthentication required
403forbiddenNo access to mailbox
404not_foundEmail not found
422send_failedSMTP delivery failed
503service_unavailableMail server offline

Rate Limits

EndpointLimit
Send100/hour per user
Inbox300/hour per user
Attachments50/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:

FieldDescription
tracking_idUnique ID embedded in the pixel URL
to_emailRecipient email address
subjectEmail subject line
sent_atTimestamp when email was sent
is_readWhether email has been opened
read_atTimestamp of first open
read_countNumber of times opened
first_read_ipIP address of first open
last_read_ipIP address of most recent open
user_agentBrowser/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