---
title: "Preview a translation"
description: "What `translate` on a send would produce, with nothing sent and nothing stored."
url: "https://openemail.uk/docs/api/emails/translate"
area: "API"
category: "Emails"
---

# Preview a translation

What `translate` on a send would produce, with nothing sent and nothing stored.

`POST /emails/translate`

## POST /emails/translate

What `translate` on a send would produce, with nothing sent and nothing stored.

## The request

The same three options a send resolves, minus the envelope, run through the same function the send path calls. That identity is the whole value of the endpoint: a preview with its own code would be a promise we do not keep, and the day the two drifted, the thing on somebody’s screen and the thing in the recipient’s inbox would differ with nothing to say so.

**Parameters**

- `to` (string, required): The language to write in. A BCP-47 code (`de`), an English name ("German") or the language’s own name ("Deutsch"). The response tells you which code it resolved to, and that is the form to store if you are keeping a language per contact.
- `html` (string): The HTML body, up to a megabyte. One of html, text or subject is required.
- `text` (string): The plain-text part. Translated independently of `html`, with its own length check.
- `subject` (string): The subject LINE: a string, not the boolean it is under `translate` on a send. The two are different questions: there you are saying whether to translate a subject we already hold, here you are handing one over.
- `from` (string): What you wrote it in, in any of the same three forms. Stating it skips the detection call.
- `includeOriginal` (boolean): Whether the returned `html` already carries your original beneath the translation. Defaults to true.

> Unknown keys are a 422, as everywhere else. A request with none of html, text or subject is a 422 on `html`: "One of html, text or subject is required".

## Preview it

The round trip the composer makes before showing somebody what they are about to send.

**curl**

```
curl -X POST "$OE/emails/translate" -H "$AUTH" -H "Content-Type: application/json" \
  -d '{
    "subject": "Your September invoice",
    "html": "<p>Invoice attached. Payment is due on the 14th.</p>",
    "to": "de"
  }'
```

**Response**

```
{
  "object": "translation",
  "language": { "code": "de", "label": "German", "native": "Deutsch", "flag": "🇩🇪", "rtl": false },
  "detectedSourceLanguage": {
    "code": "en", "label": "English", "native": "English", "flag": "🇬🇧", "rtl": false
  },
  "subject": "Ihre Rechnung für September",
  "html": "<p>Rechnung im Anhang. Zahlbar bis zum 14.</p>\n<div style=\"margin:28px 0 0;padding:14px 0 0;border-top:1px solid #d6dae0\">\n<div style=\"margin:0 0 10px;font-size:12px;line-height:1.5;color:#6b7280\">Ursprüngliche Nachricht (English)</div>\n<div><p>Invoice attached. Payment is due on the 14th.</p></div>\n</div>",
  "text": null,
  "includeOriginal": true
}
```

> `html`, `text` and `subject` come back null rather than absent for a field you did not send, so a client can render the answer without remembering what it asked.

> `detectedSourceLanguage` is null when detection abstained. That is a real answer and not a failure. A body of names, numbers and links gives it nothing to read, and the only consequence is that your original is captioned without a language.

> `includeOriginal` is echoed because it changes what `html` contains. With it on the body already carries your original beneath the translation, and appending your own copy sends it twice.

## Preview, edit, send

The shape this is built for is preview, EDIT, send: show a person the translation, let them change it, then send what they approved as an ordinary `html` and `subject` with no `translate` on the request at all. What they approved is then word for word what leaves.

**curl**

```
curl -X POST "$OE/emails" -H "$AUTH" -H "Content-Type: application/json" \
  -d '{
    "from": "billing@acme.com",
    "to": ["ada@example.com"],
    "subject": "Ihre Rechnung für September",
    "html": "<p>Rechnung im Anhang. Zahlbar bis zum 14.</p>"
  }'
```

> Sending with `translate` after previewing translates a second time and throws the edits away. The send would go out in wording nobody has read, which is the one failure the preview exists to prevent.

## What it costs, and what it does not do

- Three model calls (the body, the subject, and one to work out what you wrote in) issued together, so the wait is the longest of the three rather than their sum. Stating `from` drops the third. It is the same cost as sending with `translate`, so preview once rather than per revision.
- Nothing is sent, no row is written, and no id comes back. There is nothing here to cancel or retrieve later.
- It translates and does nothing else. It does not proofread, it does not improve the writing, and it never answers the message.
- Names, companies, links, order numbers, prices and dates come back as they went in, so the translation can be checked against the original line by line.
- Quoted history is not stripped, unlike the reading half. What you hand over is what is translated, which is right for a composer, where the body is only what somebody just wrote, and worth knowing if you post a whole reply chain.
- Scoped `emails:send`, with no scope of its own: it grants nothing a sender could not already do, and a scope nobody can tell apart from `emails:send` on a consent screen makes every other scope on that list mean slightly less.

> The body is capped at the same megabyte a send allows, but translation itself refuses anything over 30,000 characters with `translation_too_long`. The failure codes are the ones a translated send returns, listed under Send an email.
