# Send an email

> POST /emails — send a single transactional email.

`POST /emails`

Send a single email from a verified domain. The `from` address must belong to a domain you have verified; provide at least one of `html` or `text`. Returns the created email's `id`.

Pass an optional `Idempotency-Key` header to make retries safe — see [Idempotency keys](https://www.mailblastr.com/docs/emails/idempotency).

## Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | string | Yes | Bearer API key, e.g. `Bearer mb_xxxxxxxxx`. |
| `Idempotency-Key` | string | No | Optional unique key so a retried request is processed only once (remembered 24h). |

## Body parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `from` | string | Yes | Sender address on a verified domain. Accepts `Name <addr@domain.com>` or a bare address. |
| `to` | string | string[] | Yes | Recipient address(es). Between 1 and 50 recipients. |
| `subject` | string | Yes | The email subject line. |
| `html` | string | No | HTML body. Provide `html` or `text` (or both). Markdown-style `[text](url)` links and bare URLs (`https://…` / `www.…`) in the body text are converted to tracked hyperlinks automatically at send time; content already inside `<a>` tags, attribute values, and `<pre>`/`<code>` blocks is left untouched. |
| `text` | string | No | Plain-text body. Provide `text` or `html` (or both). |
| `preview_text` | string | No | Inbox preview text (preheader) shown next to the subject in the recipient's inbox list. Injected as a hidden element at the top of the HTML body — never visible in the opened email, and excluded from the plain-text part. Max **150 characters**. |
| `cc` | string | string[] | No | Carbon-copy recipient(s). Up to 50. |
| `bcc` | string | string[] | No | Blind carbon-copy recipient(s). Up to 50. |
| `reply_to` | string | string[] | No | Reply-To address(es). |
| `headers` | object | No | Map of custom MIME header name → value. See [Custom headers](https://www.mailblastr.com/docs/emails/headers). |
| `attachments` | object[] | No | Files to attach (max 40MB per email, after Base64 encoding). Each item is `{ filename, content | path, content_type, content_id }`. See [Attachments](https://www.mailblastr.com/docs/emails/attachments). |
| `tags` | object[] | No | Custom data as key/value pairs: `{ name, value }`. See [Tags](https://www.mailblastr.com/docs/emails/tags). |
| `scheduled_at` | string | No | Schedule the email to be sent later. Natural language (e.g. `in 1 min`) or ISO 8601 (e.g. `2026-08-05T11:52:01.858Z`). See [Schedule email](https://www.mailblastr.com/docs/emails/schedule). |
| `topic_id` | string | No | Topic ID for subscription handling. Each `to`/`cc`/`bcc` address is checked against the topic: recipients who are unsubscribed from the topic are **skipped** (removed from the recipient lists) and the message is sent to the rest. If every `to` recipient is skipped, the request is rejected with a `validation_error`. Addresses that are not contacts are always kept. An unknown `topic_id` returns a `validation_error`. |
| `template` | object | No | Send using a published template instead of inline body: `{ id, variables }`. `id` is the template id or alias; `variables` is an object of key/value pairs. When a `template` is set you cannot also send `html`/`text`; `from`, `subject`, and `reply_to` in the payload take precedence over the template defaults. |

### attachments[] properties

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `filename` | string | No | Name of the attached file. |
| `content` | string | No | Content of the attached file, passed as a Base64 string. Provide `content` or `path`. |
| `path` | string | No | URL where the attachment file is hosted; fetched at send time. Provide `path` or `content`. |
| `content_type` | string | No | Content type for the attachment. Derived from `filename` when not set. |
| `content_id` | string | No | Embeds the file as an inline image: reference it in your HTML via `<img src="cid:...">`. |

### tags[] properties

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | The name of the email tag. ASCII letters (a–z, A–Z), numbers (0–9), underscores, or dashes only; max 256 characters. |
| `value` | string | Yes | The value of the email tag. ASCII letters (a–z, A–Z), numbers (0–9), underscores, or dashes only; max 256 characters. |

> **Note:** The `Idempotency-Key` header should be unique per API request, has a maximum length of **256 characters**, and expires after **24 hours**.

## Request

**Node.js**

```js
import { MailBlastr } from 'mailblastr';

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"],
  "subject": "Hello from MailBlastr",
  "html": "<p>It works!</p>"
});
console.log({ data, error });
```

**Ruby**

```ruby
require "mailblastr"

Mailblastr.api_key = "mb_xxxxxxxxx"

Mailblastr::Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "delivered@example.com"
  ],
  "subject": "Hello from MailBlastr",
  "html": "<p>It works!</p>"
})
```

**PHP**

```php
$mailblastr = Mailblastr::client('mb_xxxxxxxxx');

$mailblastr->emails->send([
  'from' => "Acme <hello@yourdomain.com>",
  'to' => [
    "delivered@example.com"
  ],
  'subject' => "Hello from MailBlastr",
  'html' => "<p>It works!</p>"
]);
```

**Python**

```python
import mailblastr

mailblastr.api_key = "mb_xxxxxxxxx"

mailblastr.Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "delivered@example.com"
  ],
  "subject": "Hello from MailBlastr",
  "html": "<p>It works!</p>"
})
```

**Go**

```go
import "github.com/shekhu10/mailblastr-sdks/mailblastr-go"

client := mailblastr.NewClient("mb_xxxxxxxxx")

params := &mailblastr.SendEmailRequest{
    From:    "Acme <hello@yourdomain.com>",
    To:      []string{"delivered@example.com"},
    Subject: "hello world",
    Html:    "<p>it works!</p>",
}
sent, err := client.Emails.Send(params)
```

**Rust**

```rust
use mailblastr::{Mailblastr, CreateEmailBaseOptions};

let mb = Mailblastr::new("mb_xxxxxxxxx");

let email = CreateEmailBaseOptions::new(
    "Acme <hello@yourdomain.com>",
    ["delivered@example.com"],
    "hello world",
).with_html("<p>it works!</p>");
let _sent = mb.emails.send(email).await?;
```

**Java**

```java
import com.mailblastr.*;

Mailblastr mailblastr = new Mailblastr("mb_xxxxxxxxx");

SendEmailRequest request = SendEmailRequest.builder()
    .from("Acme <hello@yourdomain.com>")
    .to("delivered@example.com")
    .subject("hello world")
    .html("<p>it works!</p>")
    .build();
mailblastr.emails().send(request);
```

**.NET**

```csharp
using Mailblastr;

IMailblastr mailblastr = MailblastrClient.Create("mb_xxxxxxxxx");

var resp = await mailblastr.EmailSendAsync(new EmailMessage
{
    From = "Acme <hello@yourdomain.com>",
    To = "delivered@example.com",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
});
```

**cURL**

```bash
curl -X POST 'https://api.mailblastr.com/emails' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"],
  "subject": "Hello from MailBlastr",
  "html": "<p>It works!</p>"
}'
```

**CLI**

```bash
mailblastr emails send \
  --from 'Acme <hello@yourdomain.com>' \
  --to 'delivered@example.com' \
  --subject 'Hello from MailBlastr' \
  --html '<p>It works!</p>'
```

## Response

```json
{
  "id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794"
}
```

## Errors

Returns `missing_required_field` if `from`, `to`, or `subject` is missing; `validation_error` if neither `html` nor `text` is provided, if `to` is outside 1–50 recipients, or if the `from` domain is not verified; `invalid_from_address` / `invalid_to_address` for malformed addresses; and `409 concurrent_idempotent_requests` if a request with the same in-flight `Idempotency-Key` is already processing. See the [error reference](https://www.mailblastr.com/docs/api/errors).
