UTF-7 encoder and decoder
Encode text as UTF-7 so it survives seven-bit ASCII channels: café becomes caf+AOk-, and decoding brings back the original word. English letters stay readable; only other characters go into short shifted runs. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text
- café
- Calculation mode
- Encode
- Result
- caf+AOk-
- Encoding
- utf-7
- Input length
- 4
- Output length
- 8
This UTF-7 encoder converts plain Unicode text into the seven-bit-safe UTF-7 transformation defined in RFC 2152 and decodes UTF-7 strings back to readable Unicode. The engine is fully deterministic: the same input and mode always produce the same result, with no network calls, no random salts, and no date-dependent shortcuts. Common checks include encoding café to caf+AOk- and decoding that string back to the original word.
What UTF-7 is and what this tool returns
UTF-7 is a content transfer style encoding for Unicode that was designed so text could travel through systems that only guaranteed seven-bit ASCII safety. Characters from the direct set — letters, digits, a short punctuation list, optional printable ASCII, and ordinary white space — appear as themselves, so English prose stays human-readable in the encoded form.
Any character outside that set, including accented Latin letters, Greek, CJK, emoji, and other non-BMP code points, is collected into a shifted run: a plus sign, a modified Base64 body with no padding equals signs, and an optional hyphen terminator when the next character would otherwise be absorbed into the Base64 alphabet. A literal plus sign is a special case written as plus-hyphen so it never starts an accidental shift.
Where you still run into UTF-7
Developers meet UTF-7 when they inspect historical mail encodings, reproduce interoperability cases from RFC 2152 examples such as the smiling face sequence Hi Mom -+Jjo!, or confirm that a café accent becomes a short shifted run rather than opaque Base64 for the whole message. Frontend and support teams decode UTF-7 snippets during ticket investigation without pasting data into ad-hoc scripts that mishandle the hyphen terminator or treat plus-hyphen as an empty shift.
Backend services encode configuration samples or short multilingual strings before putting them on restricted seven-bit paths where eight-bit clean transport is not guaranteed. Quality engineers generate deterministic encode and decode pairs for contract tests so a library that claims UTF-7 support cannot silently change terminator rules or drop residual characters after a shifted run. Pair it with quoted-printable and Base64 helpers when you need related transfer encodings, and with other text tools when you are building a small lab of free, deterministic encoders.
What you can do with it
Legacy mail debugging
Encode or decode UTF-7 snippets from historical messages so accents and shifted Base64 runs match what older gateways expected.
Seven-bit path prep
Turn Unicode plain text into transport-safe UTF-7 before sending through restricted ASCII-only channels.
FAQ
What does the UTF-7 encoder cost?
It is free in your browser on this page.
How is UTF-7 different from Base64 or UTF-8?
UTF-8 is a byte encoding of Unicode. Base64 encodes every byte into an opaque alphabet. UTF-7 keeps most ASCII readable and only shifts non-direct characters into plus-sign Base64 runs of UTF-16BE units.
What happens if a shift sequence is malformed?
A trailing lone plus, an empty Base64 body after plus, or an odd decoded byte length are all rejected rather than guessed.
Is the result deterministic?
Yes. The same text and mode always produce the same result with no network, randomness, or date-dependent behavior.
Why does café become caf+AOk- in UTF-7?
The letters c, a and f belong to the direct set, so they stay as they are. The é does not, so it goes into a shifted run: a plus sign, a short Base64 body without padding, and a closing hyphen.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/enc/utf7 \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"café"}'const res = await fetch("https://api.kit.forhosting.com/enc/utf7", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "café"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/utf7",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "café"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/utf7", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"café"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"café"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/utf7", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "café"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.utf7",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Use it free in the browser for mail debugging and Unicode practice, or call the API at $0.002 per successful request when pipelines need reproducible UTF-7 transforms in CI and backend services.
What UTF-7 is and what this tool returns
This page always follows that RFC 2152 contract for plain text: encode mode walks Unicode code points, maps direct characters through, packs non-direct runs as big-endian UTF-16 code units, and emits the shifted Base64 form; decode mode copies direct text, expands shifted runs, and rejects empty or incomplete Base64 bodies instead of guessing. The JSON response includes result for the transformed string, mode echoing encode or decode, encoding fixed to utf-7, and input_length plus output_length measured in JavaScript string length so tests can assert sizes. There is no streaming path and no silent repair of broken shifts: either the string is valid UTF-7 or the request fails with invalid_input. If you need opaque binary packing, prefer Base64 or Base64url endpoints; if you need mailbox-name IMAP modified UTF-7 with an ampersand introducer, that is a different alphabet and is not this landing.
How text and mode are read and how results stay reproducible
Encode accepts any Unicode string, walks code points so surrogate pairs outside the basic multilingual plane stay intact, emits Set D and Set O characters and white space as themselves, maps a bare plus to plus-hyphen, and wraps non-direct runs in shifted modified Base64. After bytes are recovered they are interpreted as UTF-16BE code units and reassembled into a JavaScript string. The preferred payload field is text, with aliases input, value, and s so forms, query strings, and SDK clients can reuse the same contract without renaming columns. Mode defaults to encode and accepts decode explicitly; aliases op, direction, and action map to the same switch for scripts that already use those names. Decode requires a well-formed UTF-7 string: a lone plus at the end of input, a plus followed by a non-Base64 character that is not hyphen, an empty Base64 body, or a Base64 body that expands to an odd number of bytes all fail with a clear invalid_input message naming the malformed shift sequence. Pair the free browser run on this page with the priced API when you need the identical mathematical result inside an automated pipeline without re-implementing UTF-7 tables yourself. Invalid inputs return invalid_input and are not charged, which keeps validation cheap while successful transforms remain a fixed item price of $0.002.
Where UTF-7 fits in mail, legacy gateways, and test fixtures
Educators use the same tool when teaching the difference between UTF-8 byte hex dumps, quoted-printable equals-hex escapes, and UTF-7 plus-sign shifted Base64 for mostly textual payloads. On this page the work runs entirely in your browser; through the API each successful lookup costs $0.002, failed validation is not charged, and nothing is stored after the response returns. That split — free interactive exploration and a priced, identical API — matches the rest of the KIT tier-A catalog and lets you move from a classroom demo to an automated pipeline without changing the encoded result.
Integration use cases
RFC 2152 fixture generation
Produce reproducible UTF-7 strings for unit tests, golden files, and interoperability checks against RFC examples.
Technical questions
What modes are supported?
mode=encode (default) turns plain text into UTF-7. mode=decode turns a UTF-7 string back into Unicode text.