# stensul-build-email

> Creates a complete draft in one call: starts from a template or an existing email, sets the settings, uploads images by public URL and writes all the content.

Source: https://stensul.com/developers/reference/stensul-build-email/ · From the live server's tool list, 2026-09-28

- Scope: `emails:write`
- Access: write

Read the source with `stensul-read-email` first: content is addressed by position against that read (module 1 is the first module). Guardrails are hard limits. Anything that violates one is declined and listed in the result, not reshaped. The result is a report: the draft and its edit link, what was applied, warnings, skipped slots, missing images, the new `save_version` and a preview.

## Inputs

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Name for the new email. |
| `template_id` | string (24-char hex id) | no | Start from this template. Exactly one of `template_id` or `copy_of`. |
| `copy_of` | string (24-char hex id) | no | Start from a copy of this email, content and images included. Exactly one of `template_id` or `copy_of`. |
| `library_key` | string | no | Required with `template_id`; optional with `copy_of` (defaults to the source library). |
| `content` | array | no | Content by position: `[{ position, style?, elements: [{ position, type, text?, content?, imageContent?, link?, visibility?, url_tracking_parameters? }] }]`. Element `type` is `text`, `button`, `image` or `divider` and is cross-checked against the draft. |
| `subject_line` | string | no | Only if the library enables subject lines. |
| `preheader` | string | no | Only if the library enables preheaders. |
| `title` | string | no | Only if the library enables titles. |
| `language` | string | no | Language code, for example `en-US`. |
| `tags` | string[] | no | Tags. They must be configured in the library. |
| `project_id` | string (24-char hex id) | no | Project to assign the email to. |
| `active_variation_id` | string (24-char hex id) | no | Variation to activate (libraries in variations mode `all` only). Opt-in: only one the user chose. |
| `url_tracking` | object | no | Campaign-level tracking values such as `{ "utm_campaign": "spring-launch" }`. Only when the read reports URL tracking enabled; values must satisfy the library's tracking rules. |

## Example request

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "stensul-build-email",
    "arguments": {
      "name": "Northwind Coffee – Autumn blend launch",
      "template_id": "64f0c0ffee0000000000abcd",
      "library_key": "northwind_marketing",
      "subject_line": "The Autumn blend is here",
      "preheader": "Roasted in small batches. Ships this week.",
      "content": [
        {
          "position": 1,
          "elements": [
            {
              "position": 2,
              "type": "text",
              "text": "Meet the Autumn blend\nCaramel, toasted pecan and a clean finish."
            },
            {
              "position": 3,
              "type": "button",
              "text": "Shop the blend",
              "link": {
                "url": "https://northwind.example/autumn"
              }
            },
            {
              "position": 1,
              "type": "image",
              "imageContent": {
                "source_url": "https://northwind.example/img/autumn-hero.jpg",
                "alt": "A bag of Autumn blend coffee beside a steaming mug on a wooden table"
              }
            }
          ]
        }
      ]
    }
  }
}
```

## Response

A report: the new draft's edit link, what was applied, every tenant warning, every skipped slot with its reason, images still missing, the new `save_version` and a rendered preview. If a later stage fails, the report still names the draft that was created so you continue from there instead of creating another.

## Errors

| Status | Message | Cause | Fix |
| --- | --- | --- | --- |
| 401 | Authentication expired or missing | The session's authorization expired. | Sign in again when the host prompts. On a 401 or 403, the server's instructions tell the model to re-check sign-in first. |
| 403 | Insufficient OAuth scope (403): The token lacks the required scope | The API connection doesn't have the scope this tool needs. | An admin adds the scope to the API connection. Then sign in again: adding a scope revokes existing tokens. |
| 403 | API error (403): Action is unauthorized. | The signed-in user's role lacks the permission, for example `edit_campaign`. | Grant the permission to the user's role in Admin > Users & Roles. It works for other users on the same connection. |
| declined | Content declined by a guardrail | A value is outside what the template allows: an off-palette color, a size out of range, locked text. | Keep the value within the guardrail or make no change. Guardrails are enforced by Stensul and cannot be overridden from a chat. |
| 422 | Field not enabled for this library | `stensul-update-email-settings` sent a title, subject line or preheader the library doesn't enable, so the whole call is declined. | Send only fields the library enables (see `stensul-get-libraries`). |
