Inbox

Read and manage inbound emails received via IMAP.

Requires an IMAP account configured in the dashboard. Messages are polled automatically and made available via API. Supports read/flag toggling, folder management, and attachment downloads.

Endpoints

MethodPathPermission
GET
email.inbox_read
GET
email.inbox_read
PATCH
email.inbox_read
PATCH
email.inbox_read
PATCH
email.inbox_read
GET
email.inbox_read
DELETE
email.inbox_reply

List Inbox Messages

GET /api/v1/inbox

Request

Response

{
  "success": true,
  "data": [
    {
      "id": "inbox-uuid-1",
      "messageId": "<CAF%3D2026031809%40mail.example.com>",
      "fromEmail": "client@example.com",
      "fromName": "Marie Dupont",
      "replyToEmail": null,
      "toEmail": "contact@yourcompany.com",
      "subject": "Re: Invoice #2024-001",
      "isRead": false,
      "imapSeen": false,
      "isFlagged": true,
      "imapFlagged": true,
      "hasAttachments": true,
      "folder": "INBOX",
      "receivedAt": "2026-03-18T09:45:00.000Z",
      "createdAt": "2026-03-18T09:46:02.113Z",
      "_count": { "attachments": 2 }
    },
    {
      "id": "inbox-uuid-2",
      "messageId": "<renewal-8821%40vendor.com>",
      "fromEmail": "support@vendor.com",
      "fromName": null,
      "replyToEmail": "billing@vendor.com",
      "toEmail": "contact@yourcompany.com",
      "subject": "Your subscription has been renewed",
      "isRead": false,
      "imapSeen": true,
      "isFlagged": false,
      "imapFlagged": false,
      "hasAttachments": false,
      "folder": "INBOX",
      "receivedAt": "2026-03-18T08:30:00.000Z",
      "createdAt": "2026-03-18T08:31:44.007Z",
      "_count": { "attachments": 0 }
    }
  ],
  "meta": { "page": 1, "per_page": 20, "total": 87, "total_pages": 5 }
}
json

Get Inbox Message

GET /api/v1/inbox/:id

Returns the full message, including htmlBody, textBody and attachment metadata. The list endpoint omits all three.

Request

Response

{
  "success": true,
  "data": {
    "id": "inbox-uuid-1",
    "messageId": "<CAF%3D2026031809%40mail.example.com>",
    "fromEmail": "client@example.com",
    "fromName": "Marie Dupont",
    "replyToEmail": null,
    "toEmail": "contact@yourcompany.com",
    "subject": "Re: Invoice #2024-001",
    "htmlBody": "<p>Thank you for sending the invoice.</p>",
    "textBody": "Thank you for sending the invoice.",
    "isRead": false,
    "imapSeen": false,
    "isFlagged": true,
    "imapFlagged": true,
    "hasAttachments": true,
    "folder": "INBOX",
    "receivedAt": "2026-03-18T09:45:00.000Z",
    "createdAt": "2026-03-18T09:46:02.113Z",
    "attachments": [
      {
        "id": "attachment-uuid-1",
        "filename": "invoice-2024-001.pdf",
        "contentType": "application/pdf",
        "sizeBytes": 84213
      }
    ]
  }
}
json

Mark as Read

PATCH /api/v1/inbox/:id/read

Request

Response

{
  "success": true,
  "data": {
    "id": "inbox-uuid-1",
    "isRead": true,
    "imapSeen": false
  }
}
json

Toggle Flagged Status

PATCH /api/v1/inbox/:id/flag

isFlagged is Sendy's own state and takes effect immediately — the IMAP poller never overwrites it. The matching \Flagged flag is pushed to the mail server in the background, so imapFlagged in the response reflects the server state before that push and may lag by one poll. Same contract as isRead / imapSeen.

Request

Response

{
  "success": true,
  "data": {
    "id": "inbox-uuid-1",
    "isFlagged": true,
    "imapFlagged": false
  }
}
json

Move to Folder

PATCH /api/v1/inbox/:id/move

Moves the message on the IMAP server, then records the new folder. The move assigns a new UID, returned as imapUid. Moving a message to the folder it is already in is a no-op and returns without imapUid.

Request

Response

{
  "success": true,
  "data": {
    "id": "inbox-uuid-1",
    "folder": "Archive",
    "imapUid": 4212
  }
}
json

Download Attachment

GET /api/v1/inbox/:id/attachments/:attachmentId

Returns the raw file, not JSON — Content-Type, Content-Disposition and Content-Length come from the stored attachment. Get the attachment ids from GET /api/v1/inbox/:id. Errors are still JSON.

Request

Response headers

Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice-2024-001.pdf"
Content-Length: 84213
http

Delete Inbox Message

DELETE /api/v1/inbox/:id

The only inbox endpoint requiring email.inbox_reply — every other one needs email.inbox_read. The message is soft-deleted in Sendy and disappears from the list; the deletion is also pushed to the IMAP server in the background, so a mail-server failure leaves the message hidden in Sendy but still present in the mailbox.

Request

Response

{
  "success": true,
  "data": {
    "id": "inbox-uuid-1",
    "deleted": true
  }
}
json