# Create mail

URL: https://docs.hanzo.ai/docs/openapi/marketing/post-marketing-mail

> Sends one email from the org to one person, the way a person on the org's team writes back to a lead from its record.

`POST /v1/marketing/mail`

> [Marketing →](https://docs.hanzo.ai/docs/openapi/marketing) · [All API references →](https://docs.hanzo.ai/docs/openapi) · [Get started →](https://docs.hanzo.ai/docs/guides)

|               |                                          |
| ------------- | ---------------------------------------- |
| **Address**   | `https://api.hanzo.ai/v1/marketing/mail` |
| **Method**    | `POST`                                   |
| **Operation** | `post_marketing_mail`                    |
| **Auth**      | `Authorization: Bearer $HANZO_API_KEY`   |

Sends one email from the org to one person, the way a person on the org's team
writes back to a lead from its record.

It leaves by the org's own path, the one every marketing send takes: the org's
mailbox when it has one, else the platform's notify rail, and never to an
address that opted out of the org's mail, whose company did, or that the
platform blocks (Sent is false then, and that is not an error). It carries the
opt-out footer and List-Unsubscribe. The org's mailbox caps hold: at its cap
the send is refused with 429 and the time it frees.

An admin of the org acting, or SuperAdmin, may send: mail that leaves in the
org's name is the team's to write, not every member's. The send is on the audit
trail before it leaves (marketing.mail.send: the address, the subject and the
person, never the text), and the mail, sent or refused, goes on the timeline of
its person.

A named handler, not a closure, so zipdoc can lift this prose into the registry.

## Request

4 fields, body `application/json` (required).

| Field     | In   | Type   | Required | Description                                                                                  |
| --------- | ---- | ------ | -------- | -------------------------------------------------------------------------------------------- |
| `body`    | body | string | —        | Body is the mail as plain text, at most 20000 characters; a blank line separates paragraphs. |
| `person`  | body | string | —        | Person is the CRM person the mail is written to.                                             |
| `subject` | body | string | —        | Subject is the subject line, at most 200 characters on one line.                             |
| `to`      | body | string | —        | To is the one address the mail goes to.                                                      |

## Response

| Status    | Body              | Meaning |
| --------- | ----------------- | ------- |
| `200`     | marketing.MailOut | ok      |
| `default` | problem-details   | refused |

`200` body — 2 fields.

| Field  | In   | Type    | Always | Description                                                                   |
| ------ | ---- | ------- | ------ | ----------------------------------------------------------------------------- |
| `at`   | body | string  | —      | At is when it left, RFC 3339 UTC; empty when nothing left.                    |
| `sent` | body | boolean | —      | Sent is false when the address opted out of the org's mail, and nothing left. |

Failure carries the platform error shape — see [Errors](https://docs.hanzo.ai/docs/errors).

## Examples

**CLI**

```bash
hanzo marketing mail
```

**SDK**

**.ts**

```ts
import { Configuration, MarketingApi } from 'hanzoai';

const api = new MarketingApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postMarketingMail({ body: "<body>", person: "<person>" });
```

**.py**

```python
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import MarketingApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = MarketingApi(client).post_marketing_mail(body="<body>", person="<person>")
```

**.go**

```go
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.MarketingAPI.PostMarketingMail(context.Background()).Execute()
if err != nil {
	return err
}
```

**.rs**

```rust
use hanzo_client::apis::{configuration::Configuration, marketing_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = marketing_api::post_marketing_mail(&cfg, Default::default()).await?;
```

**.java**

```java
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.MarketingApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new MarketingApi(client).postMarketingMail();
```

**HTTP**

```bash
curl -X POST https://api.hanzo.ai/v1/marketing/mail \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "body": "<body>",
       "person": "<person>"
     }'
```

**MCP**

MCP reaches **marketing** through the `marketing` tool, which names its 82 operations with its own verbs — this one among them, under a name only MCP declares. `describe` explains any of them:

```bash
curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "describe",
         "arguments": {
           "op": "list_marketing_audiences"
         }
       }
     }'
```

---

[Marketing API](https://docs.hanzo.ai/docs/openapi/marketing) · [All Hanzo APIs](https://docs.hanzo.ai/docs/openapi) · [Interactive reference](https://docs.hanzo.ai/docs/openapi/reference)
