Skip to content
YuvaDocs

E-mail designs and templates

7 min read

A design is the look of a mail: blocks such as headings, text, images and buttons, and a theme with colours and fonts. You build it once in the panel, start from one of the templates that ship with Yuva, and use it for your broadcasts. The server turns it into mail HTML that works in the common mail apps, with a plain-text part and a dark mode.

Owners and admins make designs. API keys and OAuth tokens need the broadcasts:read or broadcasts:write scope. Assistants (agents) cannot use designs.

1. Start from a template

In the panel: Broadcasts, then the Designs tab. The gallery offers six starters: Newsletter, Product update, Announcement, Welcome, Event and Digest, each in English, Turkish and German. Pick one, pick the template language, and choose Use. Its images are copied into your workspace’s images, and you can change everything afterwards. New blank design starts from an empty mail with simple colours.

A design belongs to an inbox or to the whole workspace. The inbox’s sender identity fills the footer.

Over the API: POST /v1/email-designs with name and template: { "slug": "newsletter", "locale": "tr" }. GET /v1/email-templates lists the templates.

2. Edit the design

The designer opens full screen. Drag blocks from the palette (or the Layers outline), or press Enter on one to add it after the selected block. Click a block to change its settings on the right.

Block Use
Section A group of blocks on its own background. Sections do not nest.
Columns Two or three columns that stack on phones. Column widths add up to 100. Columns do not nest.
Heading Three sizes.
Text Paragraphs, lists and links.
Image An uploaded picture, with an optional link and alt text.
Button A link that looks like a button.
Divider, Spacer A thin line, empty room.
Social Links to your profiles, as icons or text.
Footer text Your own lines above the required footer.

Headings, text, footer text and button labels are edited in place. Text keeps only what mail apps handle well: bold, italic, underline, strikethrough, links, lists, line breaks and code. Links start with https://, http://, mailto: or tel:.

Every mail ends with a footer you cannot remove: the inbox’s legal name and postal address, why the person gets the mail, and the unsubscribe and preference links. A warning says when the inbox has no legal name or postal address yet.

A design holds up to 200 blocks.

Merge fields

Merge fields put each person’s own details into the mail. Insert one from the Insert menu in a text, or type it. Add a fallback after | for people whose value is empty:

Hi {{ contact.first_name | "there" }},
Field Value
contact.name The contact’s name.
contact.first_name The first word of the name.
contact.email The e-mail address.
contact.attributes.<key> An attribute of the contact, by its key.
inbox.name The inbox’s name.
list.name The list the mail goes to.
unsubscribe_url, preferences_url The person’s own links. In links, merge fields may appear only after the ?.

A field Yuva does not know is refused. A fallback is at most 100 characters. Values never turn into markup. Without a fallback the field can leave a gap such as “Hi ,”, so the designer warns you.

3. Theme and dark mode

Open Theme (shortcut T) for colours, fonts, content width (480 to 720 pixels), corner radius and direction (left to right, right to left, or automatic per text). Fonts are system stacks: system, humanist, geometric, serif and monospace; mails load no web fonts.

Readers whose mail app is in dark mode get darker colours made from yours, with text kept at 4.5:1 contrast. Under Dark mode you can set any of those colours yourself. An image of a dark logo on a transparent background can get a light plate behind it in dark mode.

4. Images

Open the image library from an image block (shortcut I), or drop files on it.

Types PNG, JPEG, GIF, WebP. SVG is refused because it can carry scripts.
Upload size At most 10 MiB; 40 megapixels and 8,000 pixels on a side.
Stored as Decoded and encoded again without EXIF, GPS or colour-profile data. Wider than 1,200 pixels it is scaled down to 1,200. WebP is stored as PNG, or JPEG when it has no transparency.
GIF Kept as it is, animation included: at most 1,200 pixels wide and 5 MiB.
Same file twice Answers with the image you already have.
Address Every image has a public /i/{token} URL on your server: no cookies, cached for a year, nothing recorded per request.

Give every image a description for screen readers, or mark it decorative. Together the images of a workspace may take YUVA_EMAIL_IMAGES_MAX_BYTES (Configuration).

An image used by a design that is not archived cannot be deleted; the panel names the designs. An image that went out in a broadcast asks for confirmation, because mail already delivered then shows a broken image. Images that no design uses and no broadcast sent are deleted 7 days after upload.

5. Previews and checks

The preview comes from the server, so it is what recipients get. Switch between Edit and Desktop, Phone and Dark with 1 to 4. Checks shows what to fix:

Warning Meaning
Hard to read Text under 4.5:1 contrast against its background, in light or dark colours.
Over 90 KB Gmail cuts a mail off at about 102 KB of HTML and hides what follows, the unsubscribe link included. The designer warns at 90 KB and again over 102 KB.
Image missing, no description An image block without an image, or without alt text.
No fallback A merge field that can be empty for some people.
Sender details missing The inbox has no legal name or postal address.

A design over 500 KB of HTML is refused.

6. Saving, versions and conflicts

The designer saves 1.5 seconds after your last change; Ctrl/Cmd + S saves at once and keeps a version. Undo and redo (Ctrl/Cmd + Z, with Shift for redo) go back 100 steps. Changes stay on your device while you are offline and are saved when you are back.

Versions (shortcut V) keeps the newest 50: one at most every 10 minutes while you edit, one for each manual save and one for each restore. Restoring saves that version as the newest one.

If someone else (or another tab of yours) saved first, a dialog offers three ways out: keep mine, save mine as a copy, or load theirs. Your edit is never dropped, and the other version stays in the versions. Whatever you pick, the other side’s version is kept there as “Kept from a conflict”, so no edit is lost.

Download JSON saves the design’s document as a file. Archive hides a design from the list; saving it again brings it back. A document made by a newer Yuva can be viewed but not changed.

Shortcuts: A add a block, T theme, I image, V versions, Ctrl/Cmd + D duplicate the block, Backspace delete it, Alt + ↑/↓ move it, Esc leaves the text and then the block.

7. The API

Everything the panel does is in the API contract. This renders a design without saving it:

curl -X POST https://support.example.com/v1/email-designs/render \
  -H "Authorization: Bearer $YUVA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inbox_id": "INBOX-ID",
    "document": {
      "schema": 1,
      "theme": {
        "width": 600,
        "font": "system",
        "colors": {
          "page": "#f4f4f5", "card": "#ffffff", "text": "#18181b", "muted": "#52525b",
          "accent": "#1d4ed8", "link": "#1d4ed8", "border": "#e4e4e7"
        }
      },
      "blocks": [
        { "id": "h", "type": "heading", "level": 1, "text": "Hello {{ contact.first_name | \"there\" }}" },
        { "id": "b", "type": "button", "label": "Read more", "url": "https://example.com/news" }
      ]
    }
  }'

The answer has html, text, size_bytes and warnings. Pass "dark": true for the dark palette. A save sends the version it started from as base_version; if the design moved on, the answer is 409 version_conflict with the current design in design. An invalid document answers 422 invalid_design with one entry per problem in errors.

Reference

Endpoints

Endpoint Use
GET, POST /v1/email-designs List (inbox_id, q, archived=true) and create from a document, a template or nothing.
GET, PUT, DELETE /v1/email-designs/{designId} Read, save (with base_version), archive.
POST /v1/email-designs/{designId}/duplicate Copy a design.
POST /v1/email-designs/render Render a document: HTML, text, size and warnings. At most 120 a minute.
GET /v1/email-designs/{designId}/versions The kept versions.
GET /v1/email-designs/{designId}/versions/{version} One version with its document.
POST /v1/email-designs/{designId}/versions/{version}/restore Save a version as the newest.
GET, POST /v1/email-images List and upload images (multipart, one file).
DELETE /v1/email-images/{imageId} Delete an image (force=true for one that was sent).
GET /v1/email-templates, GET /v1/email-templates/{slug} The gallery (locale=en, tr or de).
GET /i/{token} An image, public.
GET /email-templates/{slug}/{locale}.html, .webp A template’s preview, public.

Scopes

Scope Meaning
broadcasts:read Read designs, versions, images and templates; render.
broadcasts:write Create, save, copy, archive and restore designs; upload and delete images.

A key limited to inboxes reads the designs of its inboxes and the workspace-wide ones, and changes only designs of its inboxes. Keys made before these scopes existed do not get them.

Limits

Limit Value
Blocks in a design 200
Design document 300 KiB of JSON
Rendered HTML 90 KB warning, 102 KB clipped, 500 KB refused
Versions kept 50
Image upload 10 MiB, 40 megapixels, 8,000 pixels a side
Image width after upload 1,200 pixels
Merge field fallback 100 characters
Link 2,048 characters
Renders 120 a minute per caller
Unused images Deleted 7 days after upload

Edit this page on GitHub →