Email Testing API

REST API for domains, accounts, mailboxes, messages, and tokens. Authenticate with an X-API-KEY header; stream new messages over SSE via Mercure.

General information

The API is described by an OpenAPI v3 document, and you can try every endpoint in the interactive reference.

Usage of our service for illegal activity is strictly prohibited.

Integrations

Built something on the API - an SDK, a test helper, a CI action? Let us know and we'll list it here.

API Documentation

Base URL:

https://api.smtp.dev

Error handling

Successful requests return 200, 201, or 204. Errors return a 4xx code:

400 Bad Request: The payload is missing or malformed.

401 Unauthorized: The X-API-KEY header is missing or the key is invalid.

404 Not Found: The resource doesn't exist - check the id and the path.

405 Method Not Allowed: Wrong method for the path, e.g. PUT /tokens or POST /domains/{id}.

422 Unprocessable Entity: The payload didn't validate - a username too short, a domain that isn't yours.

429 Too Many Requests: Rate limit exceeded. Wait for the limit window to reset before retrying.

Authentication

All API requests require authentication using an API key.

To authenticate, add the following header to each request:

X-API-KEY: smtplabs_your_api_key_here

How to get it?

If you don't have an API key yet, create a new one on the API Keys page.

Example request with authentication:

curl -X GET "https://api.smtp.dev/accounts" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Rate Limiting

The API has the following rate limits:

  • 4096 requests per minute per authenticated user (sliding window)
  • When rate limited, the API will return a 429 Too Many Requests status code
  • Responses include rate limit headers: RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset

If you receive a 429 response, you should:

  1. Check the RateLimit-Reset header to know when you can retry
  2. Implement exponential backoff in your requests
  3. Add a delay between batches of requests
  4. Consider optimizing your code to make fewer API calls if possible

Domain

List Domains

GET /domains

You have to use this when creating an account, to retrieve the domain.

Returns a list of domains.

Body:

None

Params:

domain
string
Filter by domain name (partial match)
isActive
boolean
Filter by active status
page
int
The collection page number

curl Example:

curl -X GET "https://api.smtp.dev/domains?isActive=true&page=1" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "member": [
    {
      "id": "string",
      "domain": "string",
      "isActive": true,
      "createdAt": "2025-04-01T00:00:00.000Z",
      "updatedAt": "2025-04-01T00:00:00.000Z"
    }
  ],
  "view": {
    "id": "string",
    "type": "string",
    "first": "string",
    "last": "string",
    "previous": "string",
    "next": "string"
  },
  "search": {
    "type": "string",
    "template": "string",
    "variableRepresentation": "string",
    "mapping": [
      {
        "type": "string",
        "variable": "string",
        "property": "string",
        "required": true
      }
    ]
  }
}

Create a Domain

POST /domains

Creates a Domain resource.

Body:

domain
string required
Domain name. Example: example.com
isActive
boolean
Domain activation status

Params:

None

curl Example:

curl -X POST "https://api.smtp.dev/domains" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "domain": "example.com",
    "isActive": true
  }'

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "domain": "example.com",
  "isActive": true,
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Get a Domain

GET /domains/{id}

Retrieves a Domain resource by its id.

Body:

None

Params:

id
string required
The domain identifier

curl Example:

curl -X GET "https://api.smtp.dev/domains/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "domain": "example.com",
  "isActive": true,
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Delete a Domain

DELETE /domains/{id}

Deletes the Domain resource.

Body:

None

Params:

id
string required
The domain identifier

curl Example:

curl -X DELETE "https://api.smtp.dev/domains/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here"

Response:

None

(Returns status code 204 if successful.)

Update a Domain

PATCH /domains/{id}

Updates the Domain resource.

Body:

isActive
boolean required
Domain activation status

Params:

id
string required
The domain identifier

curl Example:

curl -X PATCH "https://api.smtp.dev/domains/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/merge-patch+json" \
  -H "Accept: application/json" \
  -d '{
    "isActive": true
  }'

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "domain": "example.com",
  "isActive": true,
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Account

List Accounts

GET /accounts

Retrieves the collection of Account resources.

Body:

None

Params:

address
string
Filter by account address
isActive
boolean
Filter by active status
page
int
The collection page number

curl Example:

curl -X GET "https://api.smtp.dev/accounts?address=user@example.com&isActive=true&page=1" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response

{
  "member": [
    {
      "id": "string",
      "address": "user@example.com",
      "quota": 0,
      "used": 0,
      "isActive": true,
      "isDeleted": false,
      "createdAt": "2025-04-01T00:00:00.000Z",
      "updatedAt": "2025-04-01T00:00:00.000Z"
    }
  ],
  "view": {
    "id": "string",
    "type": "string",
    "first": "string",
    "last": "string",
    "previous": "string",
    "next": "string"
  },
  "search": {
    "type": "string",
    "template": "string",
    "variableRepresentation": "string",
    "mapping": [
      {
        "type": "string",
        "variable": "string",
        "property": "string",
        "required": true
      }
    ]
  }
}

Create an Account

POST /accounts

Creates an Account resource

Body:

address
string required
Account's address. Example: user@example.com
password
string required
Account's password.
isActive
boolean
Account active status. Defaults to true.

Params

None

curl Example:

curl -X POST "https://api.smtp.dev/accounts" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "address": "user@example.com",
    "password": "SecurePassword123"
  }'

Response

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "address": "user@example.com",
  "quota": 0,
  "used": 0,
  "isActive": true,
  "isDeleted": false,
  "mailboxes": [
    {
      "id": "string",
      "path": "INBOX",
      "isSystem": true,
      "totalMessages": 0,
      "totalUnreadMessages": 0,
      "createdAt": "2025-04-01T00:00:00.000Z",
      "updatedAt": "2025-04-01T00:00:00.000Z"
    }
  ],
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

When an account is created, 5 default mailboxes are automatically created: INBOX, Sent, Trash, Drafts, and Junk. The address can receive mail immediately.

Get an Account

GET /accounts/{id}

Get an Account resource by its id

Body:

None

Params:

id
string required
The account identifier

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "address": "user@example.com",
  "quota": 0,
  "used": 0,
  "isActive": true,
  "isDeleted": false,
  "mailboxes": [
    {
      "id": "string",
      "path": "INBOX",
      "isSystem": true,
      "totalMessages": 0,
      "totalUnreadMessages": 0,
      "createdAt": "2025-04-01T00:00:00.000Z",
      "updatedAt": "2025-04-01T00:00:00.000Z"
    }
  ],
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Delete an Account

DELETE /accounts/{id}

Deletes the Account resource.

Deleted accounts can't be restored. Their mailboxes and messages are gone too.

Body:

None

Params:

id
string required
The account identifier

curl Example:

curl -X DELETE "https://api.smtp.dev/accounts/{accountId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here"

Response:

None

(Returns status code 204 if successful.)

Update an Account

PATCH /accounts/{id}

Updates the Account resource.

Body:

password
string
Account's password.
isActive
boolean
Account active status

Params:

id
string required
The account identifier

curl Example:

curl -X PATCH "https://api.smtp.dev/accounts/{accountId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/merge-patch+json" \
  -H "Accept: application/json" \
  -d '{
    "password": "NewSecurePassword456",
    "isActive": true
  }'

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "address": "user@example.com",
  "quota": 0,
  "used": 0,
  "isActive": true,
  "isDeleted": false,
  "mailboxes": [],
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Mailboxes

List Mailboxes

GET /accounts/{accountId}/mailboxes

Gets all the Mailbox resources of a given account.

Body:

None

Params:

accountId
string required
The account identifier.
page
int
The collection page number

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes?page=1" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "member": [
    {
      "@context": "string",
      "@id": "string",
      "@type": "string",
      "id": "string",
      "path": "string",
      "isSystem": false,
      "totalMessages": 0,
      "totalUnreadMessages": 0,
      "account": "string",
      "createdAt": "2025-04-07T05:53:58.747Z",
      "updatedAt": "2025-04-07T05:53:58.748Z"
    }
  ],
  "view": {
    "@id": "string",
    "type": "string",
    "first": "string",
    "last": "string",
    "previous": "string",
    "next": "string"
  },
  "search": {
    "@type": "string",
    "template": "string",
    "variableRepresentation": "string",
    "mapping": [
      {
        "@type": "string",
        "variable": "string",
        "property": "string",
        "required": true
      }
    ]
  }
}

Create a Mailbox

POST /accounts/{accountId}/mailboxes

Creates a Mailbox resource for a given account.

Body:

path
string required
Mailbox path. Example: Promotions

Params

accountId
string required
The account identifier.

curl Example:

curl -X POST "https://api.smtp.dev/accounts/{accountId}/mailboxes" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "path": "Promotions"
  }'

Response

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "path": "Promotions",
  "isSystem": false,
  "totalMessages": 0,
  "totalUnreadMessages": 0,
  "account": "string",
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Get a Mailbox

GET /accounts/{accountId}/mailboxes/{id}

Retrieves a Mailbox resource by its id.

Body:

None

Params:

accountId
string required
The account identifier.
id
string required
The mailbox identifier.

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "path": "string",
  "isSystem": false,
  "totalMessages": 0,
  "totalUnreadMessages": 0,
  "account": "string",
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Delete a Mailbox

DELETE /accounts/{accountId}/mailboxes/{id}

Deletes the Mailbox resource.

Body:

None

Params:

accountId
string required
The account identifier.
id
string required
The mailbox identifier.

curl Example:

curl -X DELETE "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here"

Response:

None

(Returns status code 204 if successful.)

Update a Mailbox

PATCH /accounts/{accountId}/mailboxes/{id}

Updates the Mailbox resource.

Body:

path
string
Mailbox path. Example: Primary

Params:

accountId
string required
The account identifier.
id
string required
The mailbox identifier.

curl Example:

curl -X PATCH "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/merge-patch+json" \
  -H "Accept: application/json" \
  -d '{
    "path": "Primary"
  }'

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "id": "string",
  "path": "Primary",
  "isSystem": false,
  "totalMessages": 0,
  "totalUnreadMessages": 0,
  "account": "string",
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Messages

List Messages

GET /accounts/{accountId}/mailboxes/{mailboxId}/messages

Retrieves the collection of Message resources for a given mailbox.

Body:

None

Params:

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
page
int
The collection page number

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages?page=1" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "member": [
    {
      "id": "string",
      "msgid": "string",
      "from": {
        "address": "string",
        "name": "string"
      },
      "to": [
        {
          "address": "string",
          "name": "string"
        }
      ],
      "cc": [
        {
          "address": "string",
          "name": "string"
        }
      ],
      "bcc": [
        {
          "address": "string",
          "name": "string"
        }
      ],
      "replyTo": [
        {
          "address": "string",
          "name": "string"
        }
      ],
      "date": "2025-04-01T00:00:00.000Z",
      "subject": "string",
      "intro": "string",
      "text": "string",
      "html": {},
      "isRead": false,
      "isFlagged": false,
      "isDeleted": false,
      "hasAttachments": false,
      "size": 0,
      "autoDeleteEnabled": false,
      "expiresAt": null,
      "flags": [],
      "verifications": {},
      "headers": [],
      "attachments": [],
      "downloadUrl": "string",
      "sourceUrl": "string",
      "createdAt": "2025-04-01T00:00:00.000Z",
      "updatedAt": "2025-04-01T00:00:00.000Z"
    }
  ],
  "view": {
    "id": "string",
    "type": "string",
    "first": "string",
    "last": "string",
    "previous": "string",
    "next": "string"
  }
}

Messages are ordered by createdAt descending (newest first). There are up to 30 messages per page. Use the view links (next, previous) to navigate between pages.

Get a Message

GET /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}

Retrieves a Message resource by its id (this has way more information than a message retrieved with List Messages)

Body:

None

Params:

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
id
string required
The message identifier.

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "id": "string",
  "msgid": "string",
  "from": {
    "address": "string",
    "name": "string"
  },
  "to": [
    {
      "address": "string",
      "name": "string"
    }
  ],
  "cc": [
    {
      "address": "string",
      "name": "string"
    }
  ],
  "bcc": [
    {
      "address": "string",
      "name": "string"
    }
  ],
  "replyTo": [
    {
      "address": "string",
      "name": "string"
    }
  ],
  "date": "2025-04-01T00:00:00.000Z",
  "subject": "string",
  "intro": "string",
  "text": "string",
  "html": {},
  "isRead": false,
  "isFlagged": false,
  "isDeleted": false,
  "hasAttachments": false,
  "size": 0,
  "autoDeleteEnabled": false,
  "expiresAt": null,
  "flags": [],
  "verifications": {},
  "threadId": "string",
  "headers": [],
  "attachments": [
    {
      "id": "string",
      "filename": "string",
      "contentType": "string",
      "disposition": "string",
      "size": 0,
      "downloadUrl": "string"
    }
  ],
  "downloadUrl": "string",
  "sourceUrl": "string",
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Delete a Message

DELETE /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}

Deletes the Message resource.

Body:

None

Params:

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
id
string required
The message identifier.

curl Example:

curl -X DELETE "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here"

Response:

None

(Returns status code 204 if successful.)

Update a Message

PATCH /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}

Updates the Message resource. For example, mark a message as read or flagged.

Body:

isRead
boolean
Set to true to mark the message as read
isFlagged
boolean
Set to true to mark the message as flagged
autoDeleteEnabled
boolean
Enable/disable auto-deletion of the message
expiresAt
string
ISO date-time when the message should expire

Params:

accountId
string required
The account identifier
mailboxId
string required
The mailbox identifier
id
string required
The message identifier

curl Example:

curl -X PATCH "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/merge-patch+json" \
  -H "Accept: application/json" \
  -d '{
    "isRead": true,
    "isFlagged": true,
    "autoDeleteEnabled": true,
    "expiresAt": "2025-05-01T00:00:00.000Z"
  }'

Response:

The response is the full updated Message object (same schema as Get a Message).

Get a Message Source

GET /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/source

Gets a Message's Source resource: the raw message as it arrived over SMTP - headers, MIME boundaries, encoded body parts.

Body:

None

Params:

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
id
string required
The message identifier.

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/source" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "@context": "string",
  "@id": "string",
  "@type": "string",
  "raw": "string"
}

The raw field contains the full RFC 822 message source. You can also use the Download a Message endpoint to download it as a .eml file.

Download a Message Attachment

GET /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/attachment/{attachmentId}

Gets a Message's attachment.

Body:

None

Params:

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
id
string required
The message identifier.
attachmentId
string required
The attachment identifier.

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/attachment/{attachmentId}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json" \
  -o welcome.pdf

Response:

Binary file content (saved to the specified output file).

For JSON metadata about the attachment:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"
{
  "id": "string",
  "filename": "string",
  "contentType": "string",
  "disposition": "string",
  "transferEncoding": "string",
  "related": true,
  "size": 0,
  "downloadUrl": "string"
}

Download a Message

GET /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/download

Downloads a Message resource.

Body:

None

Params:

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
id
string required
The message identifier.

curl Example:

curl -X GET "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/download" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -o message.eml

Response:

Binary file content (saved to the specified output file).

(Returns status code 200 if successful.)

Move a Message

PUT /accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/move

Moves a Message resource to a different mailbox.

Body:

mailbox
string required
The target mailbox identifier

Params

accountId
string required
The account identifier.
mailboxId
string required
The mailbox identifier.
id
string required
The message identifier.

curl Example:

curl -X PUT "https://api.smtp.dev/accounts/{accountId}/mailboxes/{mailboxId}/messages/{id}/move" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "mailbox": "{mailboxId}"
  }'

Response:

The response is the full Message object in its new mailbox (same schema as Get a Message).

Send a Message

POST /accounts/{accountId}/messages/send

Sends an email message from the specified account.

The from address is automatically set to the account's address, regardless of what you provide in the request body.

Body:

from
object required
Sender information. Must contain address (string) and optionally name (string). The address will be overwritten with the account's address.
to
array required
Array of recipient objects, each with address (string, required) and name (string, optional). At least one recipient is required.
cc
array
Array of CC recipient objects, each with address and name.
bcc
array
Array of BCC recipient objects, each with address and name.
replyTo
array
Array of Reply-To recipient objects, each with address and name.
subject
string
Email subject line.
text
string
Plain text body of the email.
html
string
HTML body of the email.
headers
array
Array of custom header objects, each with name (string) and value (string).
attachments
array
Array of attachment objects. See below.

Attachment object:

content
string required
Base64-encoded file content.
filename
string required
Attachment filename.
contentType
string required
MIME type. Example: application/pdf, image/png.
disposition
string
Either attachment (default) or inline.
cid
string
Content-ID for inline attachments.
At least one of text, html, or attachments must be provided.

Params:

accountId
string required
The account identifier.

curl Example:

curl -X POST "https://api.smtp.dev/accounts/{accountId}/messages/send" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "from": {
      "address": "user@example.com",
      "name": "John Doe"
    },
    "to": [
      {
        "address": "recipient@example.com",
        "name": "Jane Doe"
      }
    ],
    "subject": "Hello from smtp.dev",
    "text": "This is a test email.",
    "html": "<p>This is a <strong>test</strong> email.</p>"
  }'

Response:

None

(Returns status code 204 if successful.)

Handling Attachments

Attachment downloads are raw binary - write them to disk as-is. Use contentType to decide how to open the file, and disposition to tell inline images apart from regular attachments.

Tokens

List Tokens

GET /tokens

Retrieves the collection of Token resources.

Body:

None

Params:

name
string
Filter by token name (partial match)
page
int
The collection page number

curl Example:

curl -X GET "https://api.smtp.dev/tokens?page=1" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "member": [
    {
      "id": "string",
      "name": "My API Token",
      "description": "Used for automated testing",
      "createdAt": "2025-04-01T00:00:00.000Z",
      "updatedAt": "2025-04-01T00:00:00.000Z"
    }
  ]
}

Create a Token

POST /tokens

Creates a new API token.

Body:

name
string required
A name for the token to identify its purpose
description
string
Optional description of what the token is used for

Params:

None

curl Example:

curl -X POST "https://api.smtp.dev/tokens" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Integration Token",
    "description": "Used for automated testing"
  }'

Response:

{
  "id": "string",
  "token": "smtplabs_abcdef123456",
  "name": "My API Token",
  "description": "Used for automated testing",
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

The token field is only returned once when the token is created. It cannot be retrieved again.

Save the token value immediately as it will only be shown once and cannot be retrieved again.

Get a Token

GET /tokens/{id}

Retrieves a Token resource by its id.

Body:

None

Params:

id
string required
The token identifier

curl Example:

curl -X GET "https://api.smtp.dev/tokens/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "id": "string",
  "name": "My API Token",
  "description": "Used for automated testing",
  "createdAt": "2025-04-01T00:00:00.000Z",
  "updatedAt": "2025-04-01T00:00:00.000Z"
}

Delete a Token

DELETE /tokens/{id}

Deletes the Token resource.

Body:

None

Params:

id
string required
The token identifier

curl Example:

curl -X DELETE "https://api.smtp.dev/tokens/{id}" \
  -H "X-API-KEY: smtplabs_your_api_key_here"

Response:

None

(Returns status code 204 if successful.)

Real-time Updates

Mercure for Server-Sent Events (SSE)

Instead of traditional webhooks, we use Mercure to provide real-time updates via Server-Sent Events (SSE).

SSE is a standard technology that allows servers to push updates to web clients over HTTP, maintaining a single connection. This is more efficient than polling the API for updates.

Getting a Mercure Token

Before subscribing to real-time updates, you need to obtain a Mercure token:

GET /mercure/token

curl Example:

curl -X GET "https://api.smtp.dev/mercure/token" \
  -H "X-API-KEY: smtplabs_your_api_key_here" \
  -H "Accept: application/json"

Response:

{
  "token": "eyJhbGciOiJIUzI1NiJ9..."
}

Listening for New Messages

To listen for real-time updates about new messages:

Base URL:

https://mercure.smtp.dev/.well-known/mercure

Topic:

/accounts/{id}{+path}

Example implementation (JavaScript):

The standard EventSource API does not support custom headers. Use a library like @microsoft/fetch-event-source instead:

import { fetchEventSource } from '@microsoft/fetch-event-source'

const tokenResponse = await fetch('https://api.smtp.dev/mercure/token', {
  headers: { 'X-API-KEY': 'smtplabs_your_api_key_here' }
})
const { token } = await tokenResponse.json()

const mercureUrl = new URL('https://mercure.smtp.dev/.well-known/mercure')
// e.g. /accounts/6789abcdef012345{+path}
mercureUrl.searchParams.append('topic', `/accounts/${accountId}{+path}`)

await fetchEventSource(mercureUrl.toString(), {
  headers: {
    Authorization: `Bearer ${token}`
  },
  onmessage(event) {
    const data = JSON.parse(event.data)

    if (data['@type'] === 'Message') {
      // new message received
    }
  }
})

You'll receive updates with Account, Mailbox, or Message types depending on what changed.

Questions and suggestions

If you have any questions or suggestions, please contact us.

Tech stack

Our stack includes API-Platform, Mercure, Nuxt.js, Haraka, Caddy, MongoDB, Node.js, RockyLinux