Sending Email
Send email with policy enforcement, autonomy-level gating, and delivery tracking.
Molted Email provides multiple send endpoints depending on your use case. For most agent integrations, use the agent send endpoint which includes thread tracking, policy traces, and autonomy level gating.
Send endpoints
| Endpoint | Best for | Extra features |
|---|---|---|
POST /v1/agent/request-send | Agent integrations | Thread tracking, policy trace, scheduled sends, lease coordination |
POST /v1/outbound/send | Agentic mailbox clients | Thread projection, canary token detection, auto-thread creation |
POST /v1/send/request | Simple integrations | Basic send with policy checks |
All endpoints require Bearer authentication and enforce policy checks and autonomy levels.
Agent send (recommended)
POST https://api.molted.email/v1/agent/request-sendThis is the recommended endpoint for agent integrations. It supports thread tracking, scheduled sends, and returns a full policy decision trace.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
tenantId | string | Yes | Your tenant identifier. |
recipientEmail | string | Yes | The recipient's email address. Must be a valid email format (e.g. user@example.com). |
templateId | string | Yes | The template slug (e.g. welcome, order-confirmation). Also accepts a template ID. |
dedupeKey | string | Yes | A unique key to prevent duplicate sends. |
payload | object | Yes | Template variables and email content. |
mailboxId | string | No | Send from a specific mailbox. Required for autonomy level enforcement. |
threadId | string | No | Associate with an existing thread. |
sendReason | string | No | Annotate why the agent is sending (for audit trails). |
idempotencyKey | string | No | Alternative deduplication key. |
scheduledAt | string | No | ISO 8601 timestamp to schedule the send (minimum 60s in the future). |
humanize | boolean | No | Apply AI humanization to the email content. |
You can also pass the X-Agent-Id header to identify which agent initiated the send.
Simple send
POST https://api.molted.email/v1/send/requestThe basic send endpoint. Use this for simple integrations that don't need thread tracking or policy traces.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
tenantId | string | Yes | Your tenant identifier. |
recipientEmail | string | Yes | The recipient's email address. Must be a valid email format (e.g. user@example.com). |
templateId | string | Yes | The template slug (e.g. welcome, order-confirmation). Also accepts a template ID. |
dedupeKey | string | Yes | A unique key to prevent duplicate sends. The same key will be rejected as duplicate. |
payload | object | Yes | Template variables and email content. |
Payload fields
The payload object contains your email content and any template variables:
| Field | Type | Description |
|---|---|---|
subject | string | The email subject line. |
html | string | The HTML body of the email. |
text | string | Plain text fallback body. |
| custom keys | any | Any additional variables your template expects. |
Example request
curl -X POST https://api.molted.email/v1/send/request \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tenantId": "tenant_abc123",
"recipientEmail": "user@example.com",
"templateId": "order-confirmation",
"dedupeKey": "order-456-user@example.com",
"payload": {
"subject": "Your order has been confirmed",
"html": "<h1>Order Confirmed</h1><p>Thank you for your purchase.</p>",
"text": "Order Confirmed. Thank you for your purchase.",
"orderId": "456",
"customerName": "Jane"
}
}'Response
Queued (success)
{
"requestId": "req_abc123",
"status": "queued"
}The email has passed all policy checks and is queued for delivery.
Blocked
{
"requestId": "req_abc123",
"status": "blocked",
"reason": "rate_limited"
}The email was rejected by the policy engine. See Errors & Policy Blocks for all possible reason values.
Email format validation
The recipientEmail field (or --to in the CLI) must be a valid email address. The server validates email format before processing the request. If the address is invalid, the request is rejected with a 400 Bad Request error:
{
"statusCode": 400,
"message": ["recipientEmail must be an email"],
"error": "Bad Request"
}Validate email addresses before sending to avoid unnecessary API round-trips. At minimum, check that the value contains @ and a domain with a dot (e.g. user@example.com). Bare strings like alice or not-an-email will be rejected.
Deduplication
The dedupeKey field prevents sending the same email twice. If you submit a request with a dedupeKey that has already been used, the request is blocked with reason duplicate.
Use a deterministic key based on the action -- for example, {templateId}-{recipientEmail} or {orderId}-{recipientEmail}.
Per-recipient unsubscribe links
Include the literal placeholder {{molted:unsubscribe_url}} anywhere in your html or text content and Molted replaces every occurrence at send time with a signed, recipient-specific hosted unsubscribe URL:
{
"payload": {
"subject": "Your weekly digest",
"html": "<p>...</p><a href=\"{{molted:unsubscribe_url}}\">Unsubscribe</a>",
"text": "...\n\nUnsubscribe: {{molted:unsubscribe_url}}"
}
}How it works:
- Each recipient gets their own URL (
/u/<token>), signed and scoped to that (tenant, recipient) pair, valid for about one year. Batch sends mint a distinct URL per recipient. - Visiting the link shows a hosted confirmation page; confirming (or an RFC 8058 one-click
POST) adds a tenant-scoped suppression with reasonunsubscribe_link. Subsequent sends to that recipient are blocked by the standard suppression check. List-UnsubscribeandList-Unsubscribe-Post: List-Unsubscribe=One-Clickheaders are attached automatically when the delivery provider supports custom headers (Resend, Postmark). The body link works on every provider.- Content without the placeholder is passed through unchanged -- the substitution is strictly opt-in.
Related reading
- How to Send Your First Policy-Checked Email -- end-to-end walkthrough from signup to first send
- What Is Agent-Native Email? -- why email infrastructure needs a policy layer for AI agents