Skip to content
On this site

Receiving

The mail sent to your team: the message, its attachments, its raw source, and the one call that deletes all three.

A received message is its own resource

It is never an emails row. The two have separate ID spaces and separate reads: GET /emails/{email_id} will not find a received message, and GET /emails/receiving/{email_id} will not find one you sent. Nor does POST /emails/{id}/share accept a received ID — sharing inbound mail is not something this release does, and it answers 404.

  • created_at is when the message was received, not when we wrote the record.
  • Route on received_for, the addresses of yours the message was accepted for. to is whatever the sender wrote, and a sender can write anything.
  • html and text are stored exactly as decoded and are never sanitised at rest. Sanitise before you render them.

The received figure on Metrics is the count of messages the mail provider accepted from you for sending. It has nothing to do with inbound mail.

When a message has no content

A message we accepted but would not store is still recorded, with a dropped_reason, html and text null, and no attachments. The record exists so you can tell "nothing arrived" from "something arrived and we would not keep it", which are very different problems.

Why a message was not stored
dropped_reasonMeans
storage_quotaYour inbound storage was full. Delete some mail, or raise the cap.
daily_capYou had already received your plan's messages for the day.
virusThe message was scanned and refused. We do not store it.
parse_failedWe could not read the MIME structure. The raw source is still downloadable.

A message past its retention is a different thing again: it is removed whole, so it answers 404 rather than coming back emptied.

Attachments and the links to them

The attachments listed inside a message carry no link — minting one per part on every read of every message would be work nobody asked for. Read …/{email_id}/attachments when you want the bytes, and each part comes back with a download_url valid for fifteen minutes.

  • A part we refused to store is listed with its size and no download_url and no expires_at. Check for the field rather than assuming it.
  • A download takes no Authorization header: the signed link is the credential, so a browser can follow it without an API key ever reaching one.
  • Bytes are always served as a download, and a content type outside our allowlist — text/html and image/svg+xml among them — is handed over as application/octet-stream.

Endpoints

GET /emails/receiving

Every message sent to this team, newest first.

Query parameters

Query parameters
FieldTypeDescription
limitintegerHow many items to return, 1–100. Defaults to 20.
afterstringReturn the page that follows this item ID. Mutually exclusive with before.
beforestringReturn the page that precedes this item ID. Mutually exclusive with after.
curl -X GET "https://api.rasket.com/emails/receiving?limit=20" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
      "to": ["support@inbound.acme.example"],
      "from": "Ronald Williams <ronald.williams@example.com>",
      "subject": "Order #1042 arrived damaged",
      "message_id": "<CAF1042.damaged@mail.example.com>",
      "bcc": [],
      "cc": ["billing@example.com"],
      "reply_to": [],
      "dropped_reason": null,
      "created_at": "2026-09-09T10:16:44.902Z",
      "attachments": [
        {
          "id": "660e8400-e29b-41d4-a716-446655440000",
          "filename": "damage-report.pdf",
          "content_type": "application/pdf",
          "content_disposition": "attachment",
          "size": 20481
        }
      ]
    }
  ]
}
  • Cursors are received-email IDs. A row carries no html, text, headers or received_for; retrieve the message for those.
  • A message we recorded but would not store carries a dropped_reason and an empty attachments array.

GET /emails/receiving/{email_id}

One message, with its headers, bodies and attachment list.

Path parameters

Path parameters
FieldTypeDescription
email_id*stringThe ID of the received email.
curl -X GET "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "email",
  "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
  "to": ["support@inbound.acme.example"],
  "from": "Ronald Williams <ronald.williams@example.com>",
  "subject": "Order #1042 arrived damaged",
  "message_id": "<CAF1042.damaged@mail.example.com>",
  "bcc": [],
  "cc": ["billing@example.com"],
  "reply_to": [],
  "received_for": ["support@inbound.acme.example"],
  "html": "<p>The box was crushed on one side.</p>",
  "text": "The box was crushed on one side.",
  "headers": {
    "X-Mailer": "Apple Mail (2.3774)"
  },
  "dropped_reason": null,
  "created_at": "2026-09-09T10:16:44.902Z",
  "attachments": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440000",
      "filename": "damage-report.pdf",
      "content_type": "application/pdf",
      "content_disposition": "attachment",
      "size": 20481
    }
  ]
}
  • created_at is when the message was **received**, not when we wrote the record.
  • Route on received_for — the addresses of yours the message was accepted for — rather than on to, which is whatever the sender wrote.
  • subject and message_id are empty strings when the message carried no such header.
  • html and text are never sanitised at rest. Sanitise before you render them.
  • The raw source is not included. …/raw/download serves it as a file.
  • A message past its retention is removed whole and answers 404; there is no emptied record.

GET /emails/receiving/{email_id}/attachments

Each with a signed link to its bytes.

Path parameters

Path parameters
FieldTypeDescription
email_id*stringThe ID of the received email.

Query parameters

Query parameters
FieldTypeDescription
limitintegerHow many items to return, 1–100. Defaults to 20.
afterstringReturn the page that follows this item ID. Mutually exclusive with before.
beforestringReturn the page that precedes this item ID. Mutually exclusive with after.
curl -X GET "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440000",
      "filename": "damage-report.pdf",
      "content_type": "application/pdf",
      "content_disposition": "attachment",
      "size": 20481,
      "download_url": "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/660e8400-e29b-41d4-a716-446655440000/download?expires=1789200000&token=1f0c…",
      "expires_at": "2026-09-09T10:31:44.902Z"
    }
  ]
}
  • Cursors are attachment IDs; the page is in the order the parts appeared in the message.
  • A part we refused to store is listed with its size and **no** download_url and **no** expires_at. Check for the field before following it.
  • download_url is valid for fifteen minutes. Mint a fresh one by reading the attachment again rather than storing the link.

GET /emails/receiving/{email_id}/attachments/{attachment_id}

One part, with a fresh signed link.

Path parameters

Path parameters
FieldTypeDescription
email_id*stringThe ID of the received email.
attachment_id*stringThe ID of the attachment.
curl -X GET "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "attachment",
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "filename": "damage-report.pdf",
  "content_type": "application/pdf",
  "content_disposition": "attachment",
  "size": 20481,
  "download_url": "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/660e8400-e29b-41d4-a716-446655440000/download?expires=1789200000&token=1f0c…",
  "expires_at": "2026-09-09T10:31:44.902Z"
}
  • content_id is present only for a part that carried a Content-ID; resolve cid: references in the HTML body against it.

GET /emails/receiving/{email_id}/attachments/{attachment_id}/download

Follow the signed link and get the bytes.

Path parameters

Path parameters
FieldTypeDescription
email_id*stringThe ID of the received email.
attachment_id*stringThe ID of the attachment.

Query parameters

Query parameters
FieldTypeDescription
expires*integerPart of the signature. Copy the whole download_url; do not build this yourself.
token*stringThe link's signature, valid for fifteen minutes and for this object only.
curl -X GET "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e/download?expires=1789200000&token=1f0c9d3b8a72e5461c0d" \
  -H "User-Agent: acme-billing/1.0"
  • This route takes no Authorization header: the link carries its own signed authorization so a browser can follow it.
  • A User-Agent is still required, as it is on every other route.
  • Every refusal is a 404 with the same message — a bad signature, an expired link, an object that has been deleted, an ID from another team. The link is the credential, so which one it was is not something its holder has proven they may know.
  • The response is the file itself, not JSON. It is always served as a download, and a type outside our allowlist — text/html and image/svg+xml first among them — is handed over as application/octet-stream.

GET /emails/receiving/{email_id}/raw/download

The message exactly as it reached us, as `raw.eml`.

Path parameters

Path parameters
FieldTypeDescription
email_id*stringThe ID of the received email.

Query parameters

Query parameters
FieldTypeDescription
expires*integerPart of the signature. Copy the whole download_url; do not build this yourself.
token*stringThe link's signature, valid for fifteen minutes and for this object only.
curl -X GET "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/raw/download?expires=1789200000&token=1f0c9d3b8a72e5461c0d" \
  -H "User-Agent: acme-billing/1.0"
  • The raw source is deliberately not part of the message body: it can be as large as the whole message, and a reader who wants it wants a file.
  • This route takes no Authorization header: the link carries its own signed authorization so a browser can follow it.
  • A User-Agent is still required, as it is on every other route.
  • Every refusal is a 404 with the same message — a bad signature, an expired link, an object that has been deleted, an ID from another team. The link is the credential, so which one it was is not something its holder has proven they may know.
  • The response is the file itself, not JSON. It is always served as a download, and a type outside our allowlist — text/html and image/svg+xml first among them — is handed over as application/octet-stream.

DELETE /emails/receiving/{email_id}

Remove the message and give the storage back.

Path parameters

Path parameters
FieldTypeDescription
email_id*stringThe ID of the received email.
curl -X DELETE "https://api.rasket.com/emails/receiving/4ef9a417-02e9-4d39-ad75-9611e0fcc33c" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "email",
  "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
  "deleted": true
}
  • Permanent, and there is no soft delete: the stored objects go with the record.
  • The bytes return to this team's inbound storage quota. It is the only way to free inbound storage before retention does.
  • This is the one receiving operation a restricted sending_access key can never reach — as, in fact, none of them can.