Home

TropMail API

v1.0.0
Base URL
https://api.tropmail.com/api/v1Production server

Private inbound email API for TropMail.

Create addresses that only receive mail. List, search, read, and update messages; scan and download attachments. Official SDKs and MCP use the same contract.

Base URL

  • Production: https://api.tropmail.com/api/v1

Authentication

API keys from the TropMail dashboard (Pro and above). Keys are 32 alphanumeric characters, optionally prefixed with tm_live_. Send Authorization: Bearer <API_KEY>.

Rate limiting

Per account by plan (Pro 3 / Ultimate 10 / Enterprise 50 requests per second) — not per mailbox or per key. Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. On 429, honor Retry-After.

Response envelope

JSON responses use {success,message,data,error}. success is true and error is null on 200; on errors success is false, data is null, and message/error explain what happened. Correlate with X-Request-ID.

MCP tools receive the unwrapped data object, not this envelope. Attachment download routes return raw bytes, not JSON.

Authentication

BearerAuthhttp

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Scheme: bearer (API_KEY)

Health

Health check endpoints

Health check

GET
https://api.tropmail.com/api/v1/health

Service status check. Returns service version and timestamp. No authentication required.

Response

200OKStandardResponse

Service is healthy

Health check
curl -sS 'https://api.tropmail.com/api/v1/health'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail();
const health = await client.health();
console.log(health.status);
from tropmail import TropMail

with TropMail() as client:
    print(client.health().status)
package main

import (
	"context"
	"fmt"
	"log"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New("")
	if err != nil {
		log.Fatal(err)
	}
	h, err := client.Health(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(h.Status)
}
200
{
  "success": true,
  "message": "string",
  "data": {},
  "error": "string"
}

Mailbox

List inboxes at GET /mailboxes. Mail, search, and attachments use /mailbox/{id}/….

List mailboxes

GET
https://api.tropmail.com/api/v1/mailboxes

Inboxes this API key may see. data.mailboxes is an array of inbox summaries (it may be empty). Use an id from that list on /mailbox/{id} routes.

Response

200OKobject

List retrieved. data.mailboxes is an array of inbox summaries (may be empty).

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

List mailboxes
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailboxes' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });

const { mailboxes } = await client.mailboxes.list();
console.log(mailboxes[0]?.email);
from tropmail import TropMail

with TropMail() as client:
    boxes = client.mailboxes.list()
    print(boxes[0].email)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	listed, err := client.Mailboxes.List(ctx)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(listed.Mailboxes[0].Email)

}
{
  "success": true,
  "message": "Mailboxes retrieved successfully",
  "data": {
    "mailboxes": [
      {
        "id": "11111111-1111-1111-1111-111111111111",
        "email": "quiet-otter-1423@tropmail.com",
        "opened_count": 10,
        "closed_count": 5,
        "favorite_count": 2
      }
    ]
  },
  "error": null
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Get mailbox summary

GET
https://api.tropmail.com/api/v1/mailbox/{id}

Summary for one mailbox (opened / closed / favorite counts). Unknown or out-of-scope {id} → 404.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

Response

200OKobject

One mailbox summary in data (not wrapped in mailboxes).

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Get mailbox summary
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";

const mailbox = await client.mailboxes.get(mailboxId);
console.log(mailbox.email, mailbox.opened_count);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    mailbox = client.mailboxes.get(mailbox_id)
    print(mailbox.email, mailbox.opened_count)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	mailbox, err := client.Mailboxes.Get(ctx, mailboxID)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(mailbox.Email, mailbox.OpenedCount)

}
{
  "success": true,
  "message": "string",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "opened_count": 0,
    "closed_count": 0,
    "favorite_count": 0
  },
  "error": "string"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Emails

Email listing, details, and status updates

List emails

GET
https://api.tropmail.com/api/v1/mailbox/{id}/emails

Fetch inbox list with pagination and status filtering.

Standard success envelope.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

limitinteger[1, 100]10query
pageinteger>= 11query
statusstringallOpenCloseFavoriteBlockPhishingScamMaliciousallquery

Response

200OKobject

Emails retrieved successfully

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

List emails
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails?limit=10&page=1&status=Open' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";

const page = await client.emails.list({ mailboxId, limit: 10, page: 1, status: "Open" });
console.log(page.emails[0]?.subject);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    page = client.emails.list(mailbox_id=mailbox_id, limit=10, page=1, status="Open")
    print(page.emails[0].subject)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	page, err := client.Emails.List(ctx, tropmail.ListOptions{MailboxID: mailboxID, Limit: 10, Page: 1, Status: "Open"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(page.Emails[0].Subject)

}
{
  "success": true,
  "message": "string",
  "data": {
    "emails": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2024-01-15T09:30:00Z",
        "subject": "string",
        "from": {
          "name": "string",
          "address": "user@example.com"
        },
        "attachmentsCount": 0,
        "email_state": "Open",
        "action_status": "Favorite",
        "status": "string",
        "preview": "string"
      }
    ],
    "limit": 0,
    "page": 0,
    "total": 0
  }
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Search emails

GET
https://api.tropmail.com/api/v1/mailbox/{id}/emails/search

Full-text search across the authenticated mailbox.

Requires a non-empty query. Pagination mirrors list emails (limit 1-100, page >= 1).

Parameters

idstring<uuid>requiredpath

Mailbox UUID

querystringrequiredquery
limitinteger[1, 100]10query
pageinteger>= 11query

Response

200OKobject

Search completed successfully

400Bad RequestErrorEnvelope

Invalid request — missing search query, malformed UUID, or limit/page out of range. Envelope with success: false.

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Search emails
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails/search?query=verification&limit=10&page=1' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";

const page = await client.emails.search({ mailboxId, query: "verification", limit: 10 });
console.log(page.emails[0]?.subject);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    page = client.emails.search(mailbox_id=mailbox_id, query="verification", limit=10)
    print(page.emails[0].subject)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	page, err := client.Emails.Search(ctx, "verification", tropmail.ListOptions{MailboxID: mailboxID, Limit: 10})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(page.Emails[0].Subject)

}
{
  "success": true,
  "message": "string",
  "data": {
    "emails": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2024-01-15T09:30:00Z",
        "subject": "string",
        "from": {
          "name": "string",
          "address": "user@example.com"
        },
        "attachmentsCount": 0,
        "email_state": "Open",
        "action_status": "Favorite",
        "status": "string",
        "preview": "string"
      }
    ],
    "limit": 0,
    "page": 0
  },
  "error": "string"
}
{
  "success": false,
  "message": "Missing or invalid query",
  "data": null,
  "error": "Missing or invalid query"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Get email detail

GET
https://api.tropmail.com/api/v1/mailbox/{id}/emails/{emailId}

Retrieve full email details including content, headers, and attachments. Defaults to HTML view if no view specified.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

emailIdstring<uuid>requiredpath

Email UUID

timestampstring<date-time>query

Optional email timestamp from list/detail (speeds up lookup)

Response

200OKobject

Email retrieved successfully

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Get email detail
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails/550e8400-e29b-41d4-a716-446655440001' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const emailId = "550e8400-e29b-41d4-a716-446655440001";

const detail = await client.emails.get(mailboxId, emailId);
console.log(detail.subject);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    detail = client.emails.get(mailbox_id, "550e8400-e29b-41d4-a716-446655440001")
    print(detail.subject)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	detail, err := client.Emails.Get(ctx, mailboxID, "550e8400-e29b-41d4-a716-446655440001", tropmail.GetOptions{})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(detail.Subject)
}
{
  "success": true,
  "message": "string",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2024-01-15T09:30:00Z",
    "subject": "string",
    "from": {
      "name": "string",
      "address": "user@example.com"
    },
    "attachmentsCount": 0,
    "email_state": "Open",
    "action_status": "Favorite",
    "status": "string",
    "preview": "string",
    "to": [
      {
        "name": "string",
        "address": "user@example.com"
      }
    ],
    "cc": [
      {
        "name": "string",
        "address": "user@example.com"
      }
    ],
    "content": "string",
    "attachments": [
      {
        "attachment_id": "550e8400-e29b-41d4-a716-446655440000",
        "email_id": "550e8400-e29b-41d4-a716-446655440000",
        "filename": "string",
        "size": 0,
        "mime_type": "string",
        "content_id": "string",
        "disposition": "inline",
        "scan_status": "NotScanned",
        "scan_result": {
          "status": "NotScanned",
          "scannedAt": "2024-01-15T09:30:00Z",
          "stats": {
            "harmless": 0,
            "malicious": 0,
            "suspicious": 0,
            "undetected": 0
          },
          "engines": [
            {
              "engine": "string",
              "category": "harmless",
              "result": "string"
            }
          ],
          "hashes": {
            "sha256": "string",
            "sha1": "string",
            "md5": "string"
          },
          "error": "string"
        },
        "scanned_at": "2024-01-15T09:30:00Z"
      }
    ],
    "parts": {
      "listUnsubscribe": {
        "https": "string",
        "mailto": "string",
        "oneClick": true
      },
      "calendar": {
        "method": "REQUEST",
        "uid": "string",
        "path": "string"
      },
      "inlineCids": {}
    },
    "headers": {},
    "security": {}
  }
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Update email actions

POST
https://api.tropmail.com/api/v1/mailbox/{id}/emails/{emailId}

Update email_state (Open/Close) or action_status (Favorite, Delete, Block, etc.).

  • Provide at least one field in the body.
  • Optional timestamp (RFC3339) from list/detail speeds up the update.
  • Block marks the message and blocks that sender from future delivery to the mailbox.
  • To clear action_status, send an empty string "" (also unblocks the sender if it was Blocked).

Body

application/json
email_statestringOpenClose

Open or Close

action_statusstringFavoriteDeleteBlockPhishingScamMalicious

Apply action. Empty string clears status.

timestampstring<date-time>

Optional email timestamp from list/detail (speeds up lookup)

Parameters

idstring<uuid>requiredpath

Mailbox UUID

emailIdstring<uuid>requiredpath

Email UUID

Response

200OKStandardResponse

Email updated successfully

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Update email actions
curl -sS -X POST 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails/550e8400-e29b-41d4-a716-446655440001' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"email_state":"Open","action_status":"Favorite"}'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const emailId = "550e8400-e29b-41d4-a716-446655440001";

await client.emails.update(mailboxId, emailId, {
  emailState: "Open",
  actionStatus: "Favorite",
});
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    client.emails.update(mailbox_id, "550e8400-e29b-41d4-a716-446655440001", email_state="Open", action_status="Favorite")
package main

import (
	"context"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	status := tropmail.ActionFavorite
	_, err = client.Emails.Update(ctx, mailboxID, "550e8400-e29b-41d4-a716-446655440001", tropmail.UpdateOptions{
		EmailState:   tropmail.StateOpen,
		ActionStatus: &status,
	})
	if err != nil {
		log.Fatal(err)
	}
}
Request Body
{
  "email_state": "Open",
  "action_status": "Favorite",
  "timestamp": "2024-01-15T09:30:00Z"
}
{
  "success": true,
  "message": "string",
  "data": {},
  "error": "string"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Get email detail in specific view

GET
https://api.tropmail.com/api/v1/mailbox/{id}/emails/{emailId}/{view}

Retrieve email details with content rendered in a specific format (text, html, markdown).

For markdown: returns markdown immediately when already available. If not, this request waits until conversion finishes (up to about 60 seconds). Timeout is 504; retry the same GET.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

emailIdstring<uuid>requiredpath

Email UUID

viewstringtexthtmlmarkdownrequiredpath

Content format: text, html, or markdown

timestampstring<date-time>query

Optional email timestamp from list/detail (speeds up lookup)

Response

200OKobject

Email retrieved successfully

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Get email detail in specific view
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails/550e8400-e29b-41d4-a716-446655440001/text' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const emailId = "550e8400-e29b-41d4-a716-446655440001";

const detail = await client.emails.get(mailboxId, emailId, { view: "text" });
console.log(detail.content);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    detail = client.emails.get(mailbox_id, "550e8400-e29b-41d4-a716-446655440001", view="text")
    print(detail.content)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	detail, err := client.Emails.Get(ctx, mailboxID, "550e8400-e29b-41d4-a716-446655440001", tropmail.GetOptions{View: "text"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(detail.Content)

}
{
  "success": true,
  "message": "string",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2024-01-15T09:30:00Z",
    "subject": "string",
    "from": {
      "name": "string",
      "address": "user@example.com"
    },
    "attachmentsCount": 0,
    "email_state": "Open",
    "action_status": "Favorite",
    "status": "string",
    "preview": "string",
    "to": [
      {
        "name": "string",
        "address": "user@example.com"
      }
    ],
    "cc": [
      {
        "name": "string",
        "address": "user@example.com"
      }
    ],
    "content": "string",
    "attachments": [
      {
        "attachment_id": "550e8400-e29b-41d4-a716-446655440000",
        "email_id": "550e8400-e29b-41d4-a716-446655440000",
        "filename": "string",
        "size": 0,
        "mime_type": "string",
        "content_id": "string",
        "disposition": "inline",
        "scan_status": "NotScanned",
        "scan_result": {
          "status": "NotScanned",
          "scannedAt": "2024-01-15T09:30:00Z",
          "stats": {
            "harmless": 0,
            "malicious": 0,
            "suspicious": 0,
            "undetected": 0
          },
          "engines": [
            {
              "engine": "string",
              "category": "harmless",
              "result": "string"
            }
          ],
          "hashes": {
            "sha256": "string",
            "sha1": "string",
            "md5": "string"
          },
          "error": "string"
        },
        "scanned_at": "2024-01-15T09:30:00Z"
      }
    ],
    "parts": {
      "listUnsubscribe": {
        "https": "string",
        "mailto": "string",
        "oneClick": true
      },
      "calendar": {
        "method": "REQUEST",
        "uid": "string",
        "path": "string"
      },
      "inlineCids": {}
    },
    "headers": {},
    "security": {}
  }
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Attachments

Attachment metadata, scanning, and downloading

Scan all attachments

POST
https://api.tropmail.com/api/v1/mailbox/{id}/emails/{emailId}/scan-attachments

Start malware scans for every attachment on an email that is still NotScanned. Each new scan returns Processing right away. Read GET /mailbox/{id}/attachments/{attId} until scan_status is Clean, Malicious, Suspicious, or Unknown. Attachments that already have a result are skipped.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

emailIdstring<uuid>requiredpath

Email UUID

Response

200OKStandardResponse

Scans initiated

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Scan all attachments
curl -sS -X POST 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails/550e8400-e29b-41d4-a716-446655440001/scan-attachments' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const emailId = "550e8400-e29b-41d4-a716-446655440001";

const scans = await client.emails.scanAttachments(mailboxId, emailId);
console.log(scans);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    print(client.emails.scan_attachments(mailbox_id, "550e8400-e29b-41d4-a716-446655440001"))
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	scans, err := client.Emails.ScanAttachments(ctx, mailboxID, "550e8400-e29b-41d4-a716-446655440001")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(scans)

}
{
  "success": true,
  "message": "string",
  "data": {},
  "error": "string"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

List attachments for download

GET
https://api.tropmail.com/api/v1/mailbox/{id}/emails/{emailId}/download-attachments

List attachments on an email with an available flag (true when the object is stored, including empty files). Fetch bytes via GET /mailbox/{id}/attachments/{attId}/download.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

emailIdstring<uuid>requiredpath

Email UUID

Response

200OKStandardResponse

Download links retrieved

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

List attachments for download
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/emails/550e8400-e29b-41d4-a716-446655440001/download-attachments' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const emailId = "550e8400-e29b-41d4-a716-446655440001";

const files = await client.emails.downloadAttachments(mailboxId, emailId);
console.log(files[0]?.filename);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    files = client.emails.download_attachments(mailbox_id, "550e8400-e29b-41d4-a716-446655440001")
    print(files[0].filename)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	files, err := client.Emails.DownloadAttachments(ctx, mailboxID, "550e8400-e29b-41d4-a716-446655440001")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(files[0].Filename)

}
{
  "success": true,
  "message": "string",
  "data": {},
  "error": "string"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Get attachment metadata

GET
https://api.tropmail.com/api/v1/mailbox/{id}/attachments/{attId}

Read one attachment: filename, size, scan status, and the scan report once the scan has finished.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

attIdstring<uuid>requiredpath

Attachment UUID

Response

200OKobject

Attachment retrieved successfully

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Get attachment metadata
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/attachments/660e8400-e29b-41d4-a716-446655440002' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const attachmentId = "660e8400-e29b-41d4-a716-446655440002";

const meta = await client.attachments.get(mailboxId, attachmentId);
console.log(meta.filename, meta.scan_status);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    meta = client.attachments.get(mailbox_id, "660e8400-e29b-41d4-a716-446655440002")
    print(meta.filename, meta.scan_status)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	meta, err := client.Attachments.Get(ctx, mailboxID, "660e8400-e29b-41d4-a716-446655440002")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(meta.Filename, meta.ScanStatus)

}
{
  "success": true,
  "message": "string",
  "data": {
    "attachment_id": "550e8400-e29b-41d4-a716-446655440000",
    "email_id": "550e8400-e29b-41d4-a716-446655440000",
    "filename": "string",
    "size": 0,
    "mime_type": "string",
    "content_id": "string",
    "disposition": "inline",
    "scan_status": "NotScanned",
    "scan_result": {
      "status": "NotScanned",
      "scannedAt": "2024-01-15T09:30:00Z",
      "stats": {
        "harmless": 0,
        "malicious": 0,
        "suspicious": 0,
        "undetected": 0
      },
      "engines": [
        {
          "engine": "string",
          "category": "harmless",
          "result": "string"
        }
      ],
      "hashes": {
        "sha256": "string",
        "sha1": "string",
        "md5": "string"
      },
      "error": "string"
    },
    "scanned_at": "2024-01-15T09:30:00Z"
  },
  "error": "string"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Scan attachment

POST
https://api.tropmail.com/api/v1/mailbox/{id}/attachments/{attId}/scan

Start a malware scan for an attachment.

The response is immediate. A new scan comes back as Processing, and scan_result is empty until the scan completes (usually 1–2 minutes). Keep reading GET /mailbox/{id}/attachments/{attId} until scan_status is Clean, Malicious, Suspicious, or Unknown.

  • Already Processing: success, the scan is still running.
  • NotScanned: starts the scan and returns Processing.
  • Already finished: returns the existing status. The file is not scanned again.
  • Processing for more than 30 minutes: calling scan again starts a new scan.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

attIdstring<uuid>requiredpath

Attachment UUID

Response

200OKStandardResponse

Scan initiated or already in progress

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Scan attachment
curl -sS -X POST 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/attachments/660e8400-e29b-41d4-a716-446655440002/scan' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY' \
  -H 'Accept: application/json'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const attachmentId = "660e8400-e29b-41d4-a716-446655440002";

await client.attachments.scan(mailboxId, attachmentId);
let info = await client.attachments.get(mailboxId, attachmentId);
while (info.scan_status === "Processing") {
  await new Promise((r) => setTimeout(r, 2000));
  info = await client.attachments.get(mailboxId, attachmentId);
}
console.log(info.scan_status);
from tropmail import TropMail
import time

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    att_id = "660e8400-e29b-41d4-a716-446655440002"
    client.attachments.scan(mailbox_id, att_id)
    info = client.attachments.get(mailbox_id, att_id)
    while info.scan_status == "Processing":
        time.sleep(2)
        info = client.attachments.get(mailbox_id, att_id)
    print(info.scan_status)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	scan, err := client.Attachments.Scan(ctx, mailboxID, "660e8400-e29b-41d4-a716-446655440002")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(scan.ScanStatus)

}
{
  "success": true,
  "message": "string",
  "data": {},
  "error": "string"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Download attachment bytes

GET
https://api.tropmail.com/api/v1/mailbox/{id}/attachments/{attId}/download

Download attachment file bytes. Requires Bearer auth. Response is the raw file body, not a JSON envelope. A file whose size is 0 returns 200 with an empty body. 400 means there is no stored object.

Parameters

idstring<uuid>requiredpath

Mailbox UUID

attIdstring<uuid>requiredpath

Attachment UUID

Response

200OKstring<binary>

Attachment file bytes

400Bad RequestErrorEnvelope

Attachment exists but has no stored object (empty path). A file whose size is 0 is still downloadable.

401UnauthorizedErrorEnvelope

Missing, malformed, or unknown Bearer API key. Envelope with success: false.

403ForbiddenErrorEnvelope

Plan cannot use the API (Basic/guest) or this key cannot access the mailbox. Envelope with success: false.

404Not FoundErrorEnvelope

Mailbox, email, or attachment UUID unknown or out of this key’s scope. Envelope with success: false.

429Too Many RequestsErrorEnvelope

Account rate limit exceeded (Pro 3/s, Ultimate 10/s, Enterprise 50/s — per account, not per mailbox). Honor Retry-After and X-RateLimit-*.

Authorization

BearerAuthhttp (bearer)

TropMail API key from the dashboard. Send Authorization: Bearer <API_KEY>. Required on every /api/v1/* route except GET /health.

Download attachment bytes
curl -sS -X GET 'https://api.tropmail.com/api/v1/mailbox/11111111-1111-1111-1111-111111111111/attachments/660e8400-e29b-41d4-a716-446655440002/download' \
  -H 'Authorization: Bearer $TROPMAIL_API_KEY'
import { TropMail } from "@tropmail/sdk";

const client = new TropMail({ apiKey: process.env.TROPMAIL_API_KEY! });
const mailboxId = "11111111-1111-1111-1111-111111111111";
const attachmentId = "660e8400-e29b-41d4-a716-446655440002";

const res = await client.attachments.download(mailboxId, attachmentId);
const bytes = await res.arrayBuffer();
console.log(bytes.byteLength);
from tropmail import TropMail

with TropMail() as client:
    mailbox_id = "11111111-1111-1111-1111-111111111111"
    path = client.attachments.download_to(mailbox_id, "660e8400-e29b-41d4-a716-446655440002", "/tmp/attachment.bin")
    print(path)
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	tropmail "github.com/tropmail/tropmail-go"
)

func main() {
	client, err := tropmail.New(os.Getenv("TROPMAIL_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()
	mailboxID := "11111111-1111-1111-1111-111111111111"
	n, err := client.Attachments.DownloadTo(ctx, mailboxID, "660e8400-e29b-41d4-a716-446655440002", "/tmp/attachment.bin")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(n)
}
"<binary>"
{
  "success": false,
  "message": "Attachment unavailable",
  "data": null,
  "error": "Attachment unavailable"
}
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}
{
  "success": false,
  "message": "API access requires Pro or above",
  "data": null,
  "error": "Tier not allowed"
}
{
  "success": false,
  "message": "Mailbox not found",
  "data": null,
  "error": "Mailbox not found"
}
{
  "success": false,
  "message": "Rate limit exceeded",
  "data": null,
  "error": "Rate limit exceeded"
}

Models

StandardResponse

object

Standard JSON envelope. On success error is null and data holds the payload. On failure success is false, data is null, and message / error explain the problem.

successboolean

true for successful requests, false for errors.

messagestring

Human-readable summary for UI toasts/logging.

dataobject

The actual payload for successful responses, or null on errors.

errorstring | null

Error message string if success is false.

Example
{
  "success": true,
  "message": "string",
  "data": {},
  "error": "string"
}

EmailListItem

object
idstring<uuid>

Email UUID

timestampstring<date-time>

Email timestamp (RFC3339)

subjectstring

Email subject

fromobject
Show child attributes
namestring

Sender display name

addressstring<email>

Sender email address

attachmentsCountinteger

Number of attachments

email_statestringOpenClose

Open or Close

action_statusstring | nullFavoriteBlockPhishingScamMaliciousnull

Favorite, Block, Phishing, Scam, Malicious, or null

statusstring

Convenience field for UI. If action_status is set, matches that; otherwise matches email_state.

previewstring

First ~100 characters of plain text

Example
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2024-01-15T09:30:00Z",
  "subject": "string",
  "from": {
    "name": "string",
    "address": "user@example.com"
  },
  "attachmentsCount": 0,
  "email_state": "Open",
  "action_status": "Favorite",
  "status": "string",
  "preview": "string"
}

EmailDetail

object
idstring<uuid>

Email UUID

timestampstring<date-time>

Email timestamp (RFC3339)

subjectstring

Email subject

fromobject
Show child attributes
namestring

Sender display name

addressstring<email>

Sender email address

attachmentsCountinteger

Number of attachments

email_statestringOpenClose

Open or Close

action_statusstring | nullFavoriteBlockPhishingScamMaliciousnull

Favorite, Block, Phishing, Scam, Malicious, or null

statusstring

Convenience field for UI. If action_status is set, matches that; otherwise matches email_state.

previewstring

First ~100 characters of plain text

toArray<object>
Show child attributes
namestring
addressstring<email>
ccArray<object>
Show child attributes
namestring
addressstring<email>
contentstring

Body content in the requested view (text/html/markdown).

attachmentsArray<Attachment>
Show child attributes
attachment_idstring<uuid>
email_idstring<uuid>
filenamestring
sizeinteger>= 0

Size in bytes. 0 is a real empty file and can be downloaded.

mime_typestring
content_idstring | null

MIME Content-ID when present (inline images).

dispositionstring | nullinlineattachmentnull

inline or attachment. Null on older mail.

scan_statusstringNotScannedProcessingCleanMaliciousSuspiciousUnknown

Whether the file has been scanned. After you start a scan this is Processing until the result is ready.

scan_resultScanReport

Shaped scan report when a scan has completed (or failed).

Show child attributes
statusstringNotScannedProcessingCleanMaliciousSuspiciousUnknownrequired
scannedAtstring<date-time>required
statsobjectrequired
Show child attributes
harmlessintegerrequired
maliciousintegerrequired
suspiciousintegerrequired
undetectedintegerrequired
enginesArray<object>required
Show child attributes
enginestringrequired
categorystringharmlessmalicioussuspiciousundetectedtimeoutrequired
resultstring | nullrequired
hashesobject
Show child attributes
sha256string
sha1string
md5string
errorstring

Machine-readable failure code when the scan could not complete

scanned_atstring<date-time> | null
partsEmailParts

Optional extras from inbound (unsubscribe, calendar, inline images). Omitted when empty.

Show child attributes
listUnsubscribeobject
Show child attributes
httpsstring | null
mailtostring | null

Address only (no mailto: prefix).

oneClickboolean
calendarobject
Show child attributes
methodstringrequired
uidstring
pathstringrequired

R2 object key for the .ics file.

inlineCidsobject

Content-ID → attachment_id. Use to resolve cid: images.

headersobject

Parsed email headers

securityobject

Security analysis results (SPF/DKIM/DMARC/spam score)

Example
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2024-01-15T09:30:00Z",
  "subject": "string",
  "from": {
    "name": "string",
    "address": "user@example.com"
  },
  "attachmentsCount": 0,
  "email_state": "Open",
  "action_status": "Favorite",
  "status": "string",
  "preview": "string",
  "to": [
    {
      "name": "string",
      "address": "user@example.com"
    }
  ],
  "cc": [
    {
      "name": "string",
      "address": "user@example.com"
    }
  ],
  "content": "string",
  "attachments": [
    {
      "attachment_id": "550e8400-e29b-41d4-a716-446655440000",
      "email_id": "550e8400-e29b-41d4-a716-446655440000",
      "filename": "string",
      "size": 0,
      "mime_type": "string",
      "content_id": "string",
      "disposition": "inline",
      "scan_status": "NotScanned",
      "scan_result": {
        "status": "NotScanned",
        "scannedAt": "2024-01-15T09:30:00Z",
        "stats": {
          "harmless": 0,
          "malicious": 0,
          "suspicious": 0,
          "undetected": 0
        },
        "engines": [
          {
            "engine": "string",
            "category": "harmless",
            "result": "string"
          }
        ],
        "hashes": {
          "sha256": "string",
          "sha1": "string",
          "md5": "string"
        },
        "error": "string"
      },
      "scanned_at": "2024-01-15T09:30:00Z"
    }
  ],
  "parts": {
    "listUnsubscribe": {
      "https": "string",
      "mailto": "string",
      "oneClick": true
    },
    "calendar": {
      "method": "REQUEST",
      "uid": "string",
      "path": "string"
    },
    "inlineCids": {}
  },
  "headers": {},
  "security": {}
}

EmailParts

object

Optional MIME extras written when the message arrived.

listUnsubscribeobject
Show child attributes
httpsstring | null
mailtostring | null

Address only (no mailto: prefix).

oneClickboolean
calendarobject
Show child attributes
methodstringrequired
uidstring
pathstringrequired

R2 object key for the .ics file.

inlineCidsobject

Content-ID → attachment_id. Use to resolve cid: images.

Example
{
  "listUnsubscribe": {
    "https": "string",
    "mailto": "string",
    "oneClick": true
  },
  "calendar": {
    "method": "REQUEST",
    "uid": "string",
    "path": "string"
  },
  "inlineCids": {}
}

Attachment

object
attachment_idstring<uuid>
email_idstring<uuid>
filenamestring
sizeinteger>= 0

Size in bytes. 0 is a real empty file and can be downloaded.

mime_typestring
content_idstring | null

MIME Content-ID when present (inline images).

dispositionstring | nullinlineattachmentnull

inline or attachment. Null on older mail.

scan_statusstringNotScannedProcessingCleanMaliciousSuspiciousUnknown

Whether the file has been scanned. After you start a scan this is Processing until the result is ready.

scan_resultScanReport

Shaped scan report when a scan has completed (or failed).

Show child attributes
statusstringNotScannedProcessingCleanMaliciousSuspiciousUnknownrequired
scannedAtstring<date-time>required
statsobjectrequired
Show child attributes
harmlessintegerrequired
maliciousintegerrequired
suspiciousintegerrequired
undetectedintegerrequired
enginesArray<object>required
Show child attributes
enginestringrequired
categorystringharmlessmalicioussuspiciousundetectedtimeoutrequired
resultstring | nullrequired
hashesobject
Show child attributes
sha256string
sha1string
md5string
errorstring

Machine-readable failure code when the scan could not complete

scanned_atstring<date-time> | null
Example
{
  "attachment_id": "550e8400-e29b-41d4-a716-446655440000",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "filename": "string",
  "size": 0,
  "mime_type": "string",
  "content_id": "string",
  "disposition": "inline",
  "scan_status": "NotScanned",
  "scan_result": {
    "status": "NotScanned",
    "scannedAt": "2024-01-15T09:30:00Z",
    "stats": {
      "harmless": 0,
      "malicious": 0,
      "suspicious": 0,
      "undetected": 0
    },
    "engines": [
      {
        "engine": "string",
        "category": "harmless",
        "result": "string"
      }
    ],
    "hashes": {
      "sha256": "string",
      "sha1": "string",
      "md5": "string"
    },
    "error": "string"
  },
  "scanned_at": "2024-01-15T09:30:00Z"
}

MailboxSummary

object
idstring<uuid>
emailstring<email>
opened_countinteger
closed_countinteger
favorite_countinteger
Example
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "email": "user@example.com",
  "opened_count": 0,
  "closed_count": 0,
  "favorite_count": 0
}

ScanReport

object

Malware scan report for an attachment (engine summaries and optional file hashes).

statusstringNotScannedProcessingCleanMaliciousSuspiciousUnknownrequired
scannedAtstring<date-time>required
statsobjectrequired
Show child attributes
harmlessintegerrequired
maliciousintegerrequired
suspiciousintegerrequired
undetectedintegerrequired
enginesArray<object>required
Show child attributes
enginestringrequired
categorystringharmlessmalicioussuspiciousundetectedtimeoutrequired
resultstring | nullrequired
hashesobject
Show child attributes
sha256string
sha1string
md5string
errorstring

Machine-readable failure code when the scan could not complete

Example
{
  "status": "NotScanned",
  "scannedAt": "2024-01-15T09:30:00Z",
  "stats": {
    "harmless": 0,
    "malicious": 0,
    "suspicious": 0,
    "undetected": 0
  },
  "engines": [
    {
      "engine": "string",
      "category": "harmless",
      "result": "string"
    }
  ],
  "hashes": {
    "sha256": "string",
    "sha1": "string",
    "md5": "string"
  },
  "error": "string"
}

MailboxList

object

Inboxes this API key may see. An empty array means this key has no inboxes yet.

mailboxesArray<MailboxSummary>required
Show child attributes
idstring<uuid>
emailstring<email>
opened_countinteger
closed_countinteger
favorite_countinteger
Example
{
  "mailboxes": [
    {
      "id": "11111111-1111-1111-1111-111111111111",
      "email": "quiet-otter-1423@tropmail.com",
      "opened_count": 10,
      "closed_count": 5,
      "favorite_count": 2
    }
  ]
}

ErrorEnvelope

object

Error envelope. success is false; data is null.

successbooleanrequired

Always false on errors.

messagestringrequired

Human-readable summary for UI toasts and logs.

dataany | nullrequired

Always null on errors.

errorstring | nullrequired

Error detail string when success is false.

Example
{
  "success": false,
  "message": "Unauthorized",
  "data": null,
  "error": "Missing or invalid API key"
}