# Send Email

`POST https://api.inboxjot.com/v1/emails`

Sends one transactional email. The API answers 202 Accepted and delivers the email in the background. Track it with the returned id, in Emails, or with webhooks.

Works with a Sending or a Full key. Send an optional `Idempotency-Key` header to retry safely. See Idempotency.

## Body Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `from` | string \| null | No | Sender on a verified domain, such as `Acme <hello@acme.dev>`, 3 to 320 characters. Required unless the template sets one. |
| `to` | string \| string[] | Yes | One address or a list. An address can carry a name, such as `Jane <jane@example.com>`, up to 640 characters each. At most 50 recipients across `to`, `cc` and `bcc`. Repeated addresses are sent once. |
| `cc` | string \| string[] | No | Carbon copy recipients. One address or a list. An address can carry a name, such as `Jane <jane@example.com>`, up to 640 characters each. |
| `bcc` | string \| string[] | No | Blind carbon copy recipients. One address or a list. An address can carry a name, such as `Jane <jane@example.com>`, up to 640 characters each. |
| `reply_to` | string \| string[] | No | Addresses that replies go to. One address or a list. An address can carry a name, such as `Jane <jane@example.com>`, up to 640 characters each. Defaults to the template’s reply-to. |
| `subject` | string \| null | No | Email subject, 1 to 998 characters, without line breaks. Required unless the template sets one. |
| `html` | string \| null | No | HTML body. Send `html`, `text` or both, unless the template has content. |
| `text` | string \| null | No | Plain text body. |
| `template` | object \| null | No | Send with a template. Its from, reply-to, subject and content fill the fields you leave out. The template content is used only when you send neither `html` nor `text`. |
| `template.id` | string | Yes | The template id, such as `tpl_06d2mfk8r1az4hb7cv5ke`. |
| `template.variables` | object | No | Values for the template variables, such as `{ "first_name": "Ada" }`. They fill the subject, preheader and content. |
| `headers` | object | No | Custom headers, up to 50, each with a string value and no line breaks. Allowed names are `In-Reply-To`, `References`, `List-Unsubscribe`, `List-Unsubscribe-Post` and most `X-` headers. A few `X-` names are reserved. |
| `tags` | object[] | No | Up to 10 tags, stored with the email and passed to webhooks. Use each name once. `email_id`, `workspace_id` and `campaign_id` are reserved. |
| `tags[].name` | string | Yes | 1 to 256 letters, numbers, `_` or `-`. |
| `tags[].value` | string | Yes | 1 to 256 letters, numbers, `_` or `-`. |
| `scheduled_at` | string \| null | No | ISO 8601 time with an offset, such as `2026-10-20T09:00:00Z`, in the future and up to 30 days ahead. Leave it out to send now. |
| `attachments` | object[] | No | Up to 20 files, 30 MB in total. The whole request can be up to 45 MB. |
| `attachments[].filename` | string | Yes | The file name, 1 to 255 characters, without slashes or line breaks. |
| `attachments[].content` | string \| null | No | The file as base64. Send `content` or `path`, not both. |
| `attachments[].path` | string \| null | No | An HTTPS URL that Inboxjot downloads the file from. It must answer 200 without a redirect, within 15 seconds. |
| `attachments[].content_type` | string \| null | No | The MIME type, up to 255 characters. Leave it out and Inboxjot picks one from the file name. |
| `attachments[].content_id` | string \| null | No | A content id for an inline image, 1 to 255 characters. Use it in the HTML as `cid:` plus the id. |

## Response

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | No | The email id. Use it with Retrieve Email. |

## Request

cURL:

```bash
curl -X POST https://api.inboxjot.com/v1/emails \
  -H "Authorization: Bearer $INBOXJOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <hello@acme.dev>",
    "to": "riti@example.com",
    "subject": "Your receipt from Acme",
    "html": "<p>Thanks for your order.</p>"
  }'
```

Node.js:

```javascript
import { Inboxjot } from 'inboxjot';

const inboxjot = new Inboxjot();

const { id } = await inboxjot.emails.send({
  from: 'Acme <hello@acme.dev>',
  to: 'riti@example.com',
  subject: 'Your receipt from Acme',
  html: '<p>Thanks for your order.</p>',
});
```

Rust:

```rust
use inboxjot::{Inboxjot, SendEmail};

let client = Inboxjot::from_env()?;

let email = client
    .emails()
    .send(&SendEmail {
        from: Some("Acme <hello@acme.dev>".into()),
        to: vec!["riti@example.com".into()],
        subject: Some("Your receipt from Acme".into()),
        html: Some("<p>Thanks for your order.</p>".into()),
        ..Default::default()
    })
    .await?;
```

Go:

```go
client := inboxjot.NewClient("")

email, err := client.Emails.Send(ctx, inboxjot.SendEmailParams{
	From:    "Acme <hello@acme.dev>",
	To:      []string{"riti@example.com"},
	Subject: "Your receipt from Acme",
	HTML:    "<p>Thanks for your order.</p>",
})
```

Python:

```python
from inboxjot import Inboxjot

inboxjot = Inboxjot()

email = inboxjot.emails.send(
    {
        "from": "Acme <hello@acme.dev>",
        "to": "riti@example.com",
        "subject": "Your receipt from Acme",
        "html": "<p>Thanks for your order.</p>",
    }
)
```

## Responses

| Status | Description |
| --- | --- |
| 202 | Accepted. Inboxjot sends the email in the background. |
| 400 | A field is missing or invalid, an attachment could not be read or downloaded, or the Idempotency-Key header is not valid. |
| 401 | The API key is missing, revoked or expired. |
| 403 | The from domain is not added or not verified, the key is limited to another domain, every recipient is on the suppression list, sending is paused for the workspace, or the request comes from outside the key’s IP allowlist. |
| 409 | A request with the same Idempotency-Key is still running. Retry after one second. |
| 413 | The body is larger than 45 MB. |
| 415 | The Content-Type header is not application/json. |
| 422 | The Idempotency-Key was already used with a different request. |
| 429 | The key made too many requests, or the workspace reached its daily sending limit. Wait for the seconds in the Retry-After header. |
| 500 | Something failed on our side. Retry later. |

202:

```json
{
  "id": "eml_06d2mfk8r4tq9xv2bnc7s"
}
```

400:

```json
{
  "name": "validation_error",
  "status": 400,
  "message": "Either html or text is required",
  "errors": [
    {
      "message": "Either html or text is required",
      "location": "html"
    }
  ],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

401:

```json
{
  "name": "unauthorized",
  "status": 401,
  "message": "Unauthorized",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

403:

```json
{
  "name": "forbidden",
  "status": 403,
  "message": "acme.dev is not verified yet",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

409:

```json
{
  "name": "concurrent_idempotent_requests",
  "status": 409,
  "message": "A request with this idempotency key is still in progress. Try again later.",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

413:

```json
{
  "name": "payload_too_large",
  "status": 413,
  "message": "The request body is too large",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

415:

```json
{
  "name": "unsupported_media_type",
  "status": 415,
  "message": "The Content-Type must be application/json",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

422:

```json
{
  "name": "invalid_idempotent_request",
  "status": 422,
  "message": "This idempotency key was already used with a different request",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

429:

```json
{
  "name": "rate_limit_exceeded",
  "status": 429,
  "message": "Too many attempts. Try again later.",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```

500:

```json
{
  "name": "unknown_error",
  "status": 500,
  "message": "Something went wrong. Please try again later.",
  "errors": [],
  "request_id": "5f0c6a2e-8d1b-4c7a-9e3f-2b6d4a1c8e90"
}
```
