Mailactor

Your first conversation

Create an inbox, send an email, and read a reply.

This guide starts after onboarding. You need your Mailactor API key, a terminal with curl and jq, and an email address you control for the other side of the conversation.

Your key needs mailbox:manage, mailbox:send, mailbox:read, and delivery:read. A key with * includes these. If it is restricted to specific inboxes or reply-only sending, check your access before continuing.

1. Check your access

Store your key in your local environment. Replace YOUR_API_KEY with the key you received through onboarding. Keep the key out of source control and browser code.

export MAILACTOR_API_URL="https://api.mailactor.com"
export MAILACTOR_API_KEY="YOUR_API_KEY"

curl --fail-with-body --silent --show-error \
  "$MAILACTOR_API_URL/v1/me" \
  -H "x-api-key: $MAILACTOR_API_KEY"

Check organization.status, apiKey.scopes, and managedStarter.remaining. The response also includes your key restrictions and the current platform limits.

2. Create an inbox

Choose a unique local part for your agent. This example requests a managed address; no DNS setup is needed.

INBOX=$(curl --fail-with-body --silent --show-error \
  "$MAILACTOR_API_URL/v1/inboxes" \
  -H "x-api-key: $MAILACTOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"localPart":"research-agent","displayName":"Research Agent"}')

export INBOX_ID=$(printf '%s' "$INBOX" | jq -er '.id')
printf '%s' "$INBOX" | jq '{id, address, status}'

Save the returned id and exact address. If you get 409, list your inboxes before retrying: that name may already be in use. Inbox creation does not use an idempotency key. If its response is lost, page the complete inventory and match your requested localPart plus domainKind: "managed"; save the exact returned address. A conflict alone does not prove that your organization owns it. See creation recovery.

3. Send your first email

Set RECIPIENT to an email address you control. Keep SEND_KEY for retries of this exact message; generate a fresh key for a new email.

export RECIPIENT="you@example.com"
export SEND_KEY="first-send-$(uuidgen)"

PAYLOAD=$(jq -n --arg email "$RECIPIENT" \
  '{to:[{email:$email}],subject:"Hello from Mailactor",text:"My agent has an inbox. Reply to start a conversation!"}')

SENT=$(curl --fail-with-body --silent --show-error \
  "$MAILACTOR_API_URL/v1/inboxes/$INBOX_ID/messages" \
  -H "x-api-key: $MAILACTOR_API_KEY" \
  -H "idempotency-key: $SEND_KEY" \
  -H "Content-Type: application/json" \
  -d "$PAYLOAD")

export THREAD_ID=$(printf '%s' "$SENT" | jq -er '.message.threadId')
export SUBMISSION_ID=$(printf '%s' "$SENT" | jq -er '.submission.id')
printf '%s' "$SENT" | jq '{messageId: .message.id, threadId: .message.threadId, submissionId: .submission.id}'

The command prints selected identifiers from the response (illustrative values):

Printed identifiers (selected fields)
{
  "messageId": "msg_1123456789abcdef01234567",
  "threadId": "thr_0123456789abcdef01234567",
  "submissionId": "00000000-0000-4000-8000-000000000001"
}

The full HTTP body is {message, submission, replayed}; see the complete send response. A successful send returns 202 Accepted. It means the message and delivery submission are stored; delivery happens asynchronously.

4. Confirm delivery

Wait one second before checking the submission. For subsequent checks, wait 2 seconds, then 4 seconds, then at most 5 seconds between checks. Set a deadline for your workflow.

curl --fail-with-body --silent --show-error \
  "$MAILACTOR_API_URL/v1/submissions/$SUBMISSION_ID" \
  -H "x-api-key: $MAILACTOR_API_KEY" | jq '{status, recipients}'

Continue while the status is pending, queued, or deferred. For this single-recipient example, delivered confirms the recipient's server accepted the message. Other outcomes need attention; see delivery status. If the deadline expires, preserve the submission ID and report its actual state.

5. Receive a reply

Open the message in your other mailbox and reply normally. Mailactor receives it at your inbox address and adds it to the conversation.

curl --fail-with-body --silent --show-error \
  "$MAILACTOR_API_URL/v1/threads/$THREAD_ID?limit=20" \
  -H "x-api-key: $MAILACTOR_API_KEY" | jq '{id, messages, nextCursor}'

Look for a message with direction: "inbound". Arrival and parsing are asynchronous: use the same bounded polling schedule if it is not visible yet. Follow nextCursor when present. Do not mistake the original outbound message for an incoming reply.

You now have a two-way conversation. Next, reply through the API or register a webhook to receive notifications automatically.

On this page