Email screenshots render a captured email the way a real email client displays it. Pick a client and a theme and you get back a picture of the message after that client has rewritten it: the CSS it dropped, the width it gave the message, the colours it swapped in dark mode. No device, no virtual machine.
Every render also comes with findings, a list of what the client changed, so a test or an agent can act on the result without looking at the picture.
Email screenshots are in beta. Every render runs in one browser engine standing in for the client's own, so read it as a guide to what a client drops, clips or recolours, not as a pixel match, and expect the occasional render that is off. Report one with the flag on the render.
Screenshots are available on every plan. The Free plan renders Gmail on the desktop web only; Basic and up render every client, light and dark.
Rendering from the dashboard
- Open a captured email and switch to the Client screenshots tab.
- Tick the clients and themes you want, or open one row and click Render.
- Click a rendered row to see it, or open it full size to zoom in.
A render is stored for seven days. Opening the same email again shows the stored picture without spending another preview; after seven days the row goes back to Render.
Reading a render
Each render carries a fidelity tier, because some clients are easier to reproduce than others:
| Tier | Meaning |
|---|---|
| A | The client passes HTML through untouched. The render matches the viewport, fonts and chrome, and the picture is close to what lands in the inbox. |
| B | The client rewrites the message and the render applies that rewrite: the properties it strips, the tags it replaces, the dark-mode colour walk. Trust what was dropped and how the layout reflowed. |
| B- | Same as B, against an engine the renderer cannot reproduce (a WebKit client, or classic Outlook's Word engine). Trust "this declaration is dropped"; do not trust the exact place a line wraps. |
Two limits apply to what a render can show:
- Remote images are fetched by the renderer, so a template that loads its logo from your CDN renders with the logo. Inline
cid:images from the email's own attachments are embedded too, when they are PNG, JPEG, GIF or WebP. An SVG shows as the broken-image placeholder, remote or inline, and so it does in Gmail. - The HTML part must be under 2 MB. An email with no HTML part cannot be rendered.
Dark mode is a separate render, not a filter over the light one. Some clients recolour every colour in the message, some only the ones you did not set, and Gmail on the desktop web leaves the message alone, so it has no dark variant.
Clients
These are the clients you can render today. Each has been compared against the real client before it was published; we add more as they pass that check.
| Client | Device | Tier | Dark mode |
|---|---|---|---|
| Gmail (desktop web) | Desktop, 1600 px window, 1200 px column | B | No, Gmail on the web does not recolour messages |
| Gmail for Android | Phone, 385 px, 336 px column | B | Yes |
| Gmail for iOS | Phone, 390 px, 361 px column | B | Yes |
| Outlook.com (web) | Desktop, 1600 px window, 1089 px column | B | Yes |
| Proton Mail (web) | Desktop, 1600 px window, 1212 px column | A | Light only for now |
| Seznam Email (web) | Desktop, 1600 px window, 1234 px column | A | Yes |
| Outlook for Windows (classic) | Desktop, 1600 px window, 1016 px column | B- | Yes |
| Outlook for Windows (new) | Desktop, 1600 px window, 1073 px column | B | Light only for now |
| Apple Mail (macOS) | Desktop, 1024 px window, 800 px column | A | Yes |
Rendering from the API and the SDK
The REST API renders the same way the dashboard does: same clients, same quota, same seven day storage. All three calls need the emails:screenshot scope on the API key.
| Call | What it does |
|---|---|
GET /v1/email-clients | Lists the clients in the table above with their ids, fidelity tier and whether your plan includes them, plus the monthly quota. Needs no email. |
GET /v1/sandboxes/{sandboxId}/emails/{emailId}/screenshots | Lists every client and theme you can render, marks the ones with a stored render, and returns the monthly quota. |
POST /v1/sandboxes/{sandboxId}/emails/{emailId}/screenshots | Renders one client in one theme and returns the stored render with a signed url. |
With the JavaScript SDK:
import { writeFile } from 'node:fs/promises';
const email = await client.emails.waitFor(sandbox.id, { subject: 'Welcome' });
const shot = await client.screenshots.create(sandbox.id, email.id, {
client: 'gmail-web',
theme: 'light'
});
await writeFile('welcome-gmail.png', await client.screenshots.download(shot)); The url on a render works without an API key for 30 minutes (urlExpiresAt); list the screenshots again for a fresh link to the same stored image. The REST API returns the picture and its fidelity fields. Findings come from the MCP tool below.
Rendering from an AI agent
The MCP server exposes two tools. Both need the emails:screenshot scope on your API key or OAuth grant.
list_email_clients returns the catalogue above, so the agent picks a client id it can actually get instead of guessing one.
screenshot_email renders one captured email:
| Argument | Description |
|---|---|
email_id | The captured email. It must belong to your organization. |
clients | Profile ids from list_email_clients. Up to 4 per call; how many your plan allows per render is in the table below. Defaults to gmail-web. |
theme | light or dark. A client that does not support dark refuses the request rather than rendering light. |
force | Render again although a stored render exists. Spends a preview; only useful when the stored image no longer loads. |
block_images | Render without fetching remote images, the way a client with images off shows the message. Counted as a preview, but not stored or shown in the dashboard. |
tile | Return a tall email as several images instead of clipping it. Counted, not stored, like block_images. |
Every call renders: the result carries, per client, the image, fidelityTier, engineMismatch, findings and approximations.
A render made by an agent is the same render as one made in the dashboard or through the API. It is stored for seven days, it appears under the email's Client screenshots tab, it counts against the same monthly previews, and asking again for the same email, client and theme returns the stored render (cached: true) at no cost. Each image also has a url that opens the render in a browser with no API key, valid for 7 days (urlExpiresAt). Treat the link as a secret: anyone who has it can view that render until it expires.
A finding is plain JSON with a stable rule id:
{
"severity": "error",
"rule": "css-property-unsupported",
"property": "position",
"value": "absolute",
"message": "Gmail strips position; the badge falls into the flow"
} severity is error, warn or info. The loop an agent runs is: send, wait_for_email, screenshot_email, read the findings, fix the template, send again until nothing comes back. The Agent Skill teaches that workflow.
Previews and plan limits
One preview is one email rendered in one client in one theme. One email in four clients, light and dark, is eight previews.
| Plan | Previews per month | Clients | Clients per render | Renders a minute | Renders at once |
|---|---|---|---|---|---|
| Free | 20 | Gmail (desktop web) | 1 | 5 | 1 |
| Basic | 500 | All | 4 | 20 | 4 |
| Pro | 3,000 | All | 4 | 60 | 4 |
| Ultra | 25,000 | All | All | 120 | 4 |
Every number here holds wherever the render is asked for: the dashboard, the REST API, the SDK and the MCP tools share one quota, one rate limit and one set of renders in flight per organization.
The Free plan needs a verified email address before it can render. A failed render counts as a preview; re-rendering an email whose stored render is still live does not.
"Renders at once" counts the dashboard, the API and MCP together. A render over that number waits its turn for up to 20 seconds rather than failing, so a batch simply runs a few at a time. An MCP call that names more clients than that renders them in rounds.
We notify you at 80% and 95% of the monthly cap. At 100%, rendering pauses until the next billing cycle or until you upgrade; capture, the inbox, webhooks and the API keep working.
Reporting a wrong render
Open the render and click the flag next to the client name. Say what is off, in a sentence or two; the email, the client, the theme and a link back to that render are attached for you. The report lands in support as a bug report and we check it against the real client.
Troubleshooting
PLAN_UPGRADE_REQUIRED: the client is not on your plan. Free renders Gmail on the desktop web only.
QUOTA_EXCEEDED: this month's previews are used up. The count beside the tabs shows how many were left.
RATE_LIMITED (RATE_LIMIT_EXCEEDED on the REST API): more renders started in one minute across your organization than the plan allows. Wait for the Retry-After and try again; the dashboard renders a batch one at a time for this reason.
EMAIL_NOT_VERIFIED: the Free plan renders only once an email address on the account is confirmed. Confirm it from the link we sent at signup, or request a new one from your profile.
CONCURRENCY_LIMIT: your organization already has its plan's number of renders running and the wait for a free slot ran out. Render the batch one after another, or retry after the Retry-After. The SDK does this for you.
RENDERER_BUSY: the renderer is at capacity for everyone. Nothing was rendered and no preview was spent; retry after the Retry-After.
NO_HTML: the email has no HTML part, so there is nothing to render. TOO_LARGE: the HTML part is over 2 MB.
UNKNOWN_CLIENT: the id is not in list_email_clients (MCP) or GET /v1/email-clients (REST).
RENDER_FAILED: the renderer could not produce the picture. The message says why; try again, and if it repeats, report it.