/api/qmail/db/messages/search

GET

Full-text search across email subjects and bodies.

Description

The /api/qmail/db/messages/search endpoint performs a full-text search across the subject lines and body content of all emails in the mailbox. It returns matching emails with metadata and a short body preview, making it ideal for building search interfaces and filtering large mailboxes.

Search Scope

The search text is matched against both the subject and body fields of every email. Results are returned in reverse chronological order (newest first) and include a 200-character body preview for each match.

Query Parameters

Parameter Type Required Description
query string Yes The search text to find in email subjects and bodies.
limit integer No Maximum number of results to return. Range: 1-200. Default: 50.

Response

Returns a JSON object containing the search query, result count, and an array of matching email objects.

Response Properties

success boolean
Indicates whether the search completed successfully.
query string
The original search query echoed back.
count integer
Number of matching results returned.
results array<object>
Array of email objects matching the search query.
results[].email_id string
Unique email identifier (hex string).
results[].subject string
The email subject line.
results[].sender_sn integer (int64)
Serial number of the party. For incoming folders this is the sender; for Sent/Drafts results it is the primary recipient.
results[].sender_denomination_code integer
Denomination code of the party's address, 04 (0=bit, 1=byte, 2=kilo, 3=mega, 4=giga).
results[].sender_denomination number
Human-readable denomination value derived from sender_denomination_code.
results[].sender_address string
Canonical dotted-decimal QMail address of the party (e.g. 6.197@bit).
results[].sender_name string
Display name of the sender, resolved from the saved contacts database by serial number. Empty string when the sender is not a saved contact. Prefer this over sender_address when non-empty.
results[].sender_is_favorite boolean
Whether the resolved sender contact is a favorite. false when not a saved contact.
results[].sender_trust_level integer
Trust level of the resolved sender contact. 0 when not a saved contact.
results[].sender_class_name string
Optional class/category label on the resolved sender contact. Empty string when unset or not a saved contact.
results[].sender_description string
Optional description on the resolved sender contact. Empty string when unset or not a saved contact.
results[].sender_user_notes string
Optional private notes on the resolved sender contact. Empty string when unset or not a saved contact.
results[].recipient_count integer
Number of recipients on this email. 0 for incoming mail with no stored recipients. The recipient_* fields describe the primary (first TO) recipient.
results[].recipient_sn integer (int64)
Serial number of the primary recipient. Present when recipient_count > 0.
results[].recipient_denomination_code integer
Denomination code (04) of the primary recipient. May be -1 when unresolved.
results[].recipient_denomination number
Human-readable denomination value of the primary recipient.
results[].recipient_address string
Canonical dotted-decimal QMail address of the primary recipient. Present when its serial number and denomination are known.
results[].recipient_name string
Display name of the primary recipient, resolved from saved contacts. Empty string when not a saved contact. For Sent/Drafts results, prefer this over recipient_address when non-empty.
results[].recipient_is_favorite boolean
Whether the resolved recipient contact is a favorite. false when not a saved contact.
results[].recipient_trust_level integer
Trust level of the resolved recipient contact. 0 when not a saved contact.
results[].recipient_class_name string
Optional class/category label on the resolved recipient contact. Empty string when unset or not a saved contact.
results[].recipient_description string
Optional description on the resolved recipient contact. Empty string when unset or not a saved contact.
results[].recipient_user_notes string
Optional private notes on the resolved recipient contact. Empty string when unset or not a saved contact.
results[].received_timestamp integer (int64)
Unix timestamp (in seconds) when the email was received.
results[].sent_timestamp integer (int64)
Unix timestamp (in seconds) when the sender sent the email. May be 0 for older mail; fall back to received_timestamp.
results[].is_read boolean
Whether the email has been read.
results[].folder integer
Numeric folder identifier where the email resides.
results[].attachment_count integer
Number of attachments stored with this email. 0 when none.
results[].body_preview string
Preview of the email body (first 200 characters).

Success Response (200 OK)

{
  "success": true,
  "query": "meeting",
  "count": 2,
  "results": [
    {
      "email_id": "a1b2c3d4e5f60718293a4b5c6d7e8f90",
      "subject": "Team Meeting Tomorrow",
      "sender_sn": 1048576,
      "sender_denomination_code": 2,
      "sender_denomination": 100,
      "sender_address": "16.0.0@kilo",
      "sender_name": "Alice Johnson",
      "sender_is_favorite": true,
      "sender_trust_level": 1,
      "sender_class_name": "Work",
      "sender_description": "Finance team lead",
      "sender_user_notes": "Prefers replies before noon.",
      "recipient_count": 0,
      "recipient_name": "",
      "recipient_is_favorite": false,
      "recipient_trust_level": 0,
      "recipient_class_name": "",
      "recipient_description": "",
      "recipient_user_notes": "",
      "received_timestamp": 1736952600,
      "sent_timestamp": 1736952480,
      "is_read": false,
      "folder": 0,
      "attachment_count": 0,
      "body_preview": "Hi team, just a reminder that we have our weekly meeting tomorrow at 10am. Please bring your status updates and any blockers you want to discuss. The agenda includes project timeline review and..."
    },
    {
      "email_id": "b2c3d4e5f6071829304b5c6d7e8f90a1",
      "subject": "Re: Meeting Notes",
      "sender_sn": 197,
      "sender_denomination_code": 0,
      "sender_denomination": 1,
      "sender_address": "197@bit",
      "sender_name": "",
      "sender_is_favorite": false,
      "sender_trust_level": 0,
      "sender_class_name": "",
      "sender_description": "",
      "sender_user_notes": "",
      "recipient_count": 0,
      "recipient_name": "",
      "recipient_is_favorite": false,
      "recipient_trust_level": 0,
      "recipient_class_name": "",
      "recipient_description": "",
      "recipient_user_notes": "",
      "received_timestamp": 1736847300,
      "sent_timestamp": 1736847180,
      "is_read": true,
      "folder": 0,
      "attachment_count": 0,
      "body_preview": "Here are the notes from yesterday's meeting as discussed. Action items have been assigned and deadlines are listed below. Please review and confirm your tasks by end of day Friday."
    }
  ]
}

Error Response (400 Bad Request)

{
  "error": true,
  "message": "Missing required parameter: query",
  "code": 400
}

Error Response (500 Internal Server Error)

{
  "error": true,
  "message": "Search failed",
  "code": 500,
  "detail": "database_error"
}

Try It Out

http://localhost:8082/api/qmail/db/messages/search

Examples

cURL

# Basic search
curl "http://localhost:8082/api/qmail/db/messages/search?query=meeting"

# Search with custom limit
curl "http://localhost:8082/api/qmail/db/messages/search?query=invoice&limit=10"

# URL-encode spaces in the query
curl "http://localhost:8082/api/qmail/db/messages/search?query=project%20update&limit=25"

# Pretty print the JSON response
curl "http://localhost:8082/api/qmail/db/messages/search?query=meeting" | jq

JavaScript (async/await)

const API_BASE = 'http://localhost:8082/api';

async function searchEmails(query, limit = 50) {
    try {
        const params = new URLSearchParams({
            query: query,
            limit: limit.toString()
        });

        const response = await fetch(`${API_BASE}/qmail/db/messages/search?${params}`);

        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }

        const data = await response.json();

        console.log(`Search for "${data.query}" returned ${data.count} result(s)`);

        data.results.forEach(email => {
            const status = email.is_read ? 'Read' : 'Unread';
            // Prefer the resolved contact name; fall back to the address, then the SN.
            const who = email.sender_name || email.sender_address || `SN ${email.sender_sn}`;
            console.log(`[${status}] ${email.subject}`);
            console.log(`  From: ${who}${email.sender_is_favorite ? ' [FAV]' : ''}`);
            console.log(`  ID: ${email.email_id}`);
            console.log(`  Preview: ${email.body_preview}`);
        });

        return data;
    } catch (error) {
        console.error('Search failed:', error);
        throw error;
    }
}

// Example usage
searchEmails('meeting', 20);

Python

import requests

API_BASE = 'http://localhost:8082/api'

def search_emails(query, limit=50):
    """
    Search for emails by subject and body content.

    Args:
        query: Search text to match against subjects and bodies
        limit: Maximum results to return (1-200, default 50)

    Returns:
        Dictionary with success, query, count, and results
    """
    params = {
        'query': query,
        'limit': limit
    }

    response = requests.get(f'{API_BASE}/qmail/db/messages/search', params=params)
    response.raise_for_status()

    data = response.json()

    print(f"Search for '{data['query']}' returned {data['count']} result(s)\n")

    for email in data['results']:
        status = 'Read' if email['is_read'] else 'Unread'
        # Prefer the resolved contact name; fall back to the address, then the SN.
        who = email.get('sender_name') or email.get('sender_address') or f"SN {email['sender_sn']}"
        fav = ' [FAV]' if email.get('sender_is_favorite') else ''
        print(f"[{status}] {email['subject']}")
        print(f"  From: {who}{fav}")
        print(f"  ID: {email['email_id']}")
        print(f"  Folder: {email['folder']}")
        print(f"  Preview: {email['body_preview']}\n")

    return data

# Example usage
if __name__ == '__main__':
    results = search_emails('meeting', limit=20)