Inbox previews
DeliverabilityInbox previews
See how a design renders in real email clients before you send. In Preview, a client switcher simulates each client's rendering quirks, so you catch breakage (Outlook's square corners, Gmail-mobile stripping <style>) without leaving the editor.
preview.inbox (see Plans & entitlements). The switcher is a client-side simulation of documented quirks. For real screenshots, connect your own preview service (below).Simulated clients#
| Prop | Type | Default | Description |
|---|---|---|---|
Apple Mail | WebKit | - | Near-full CSS, the reference render. |
Gmail (Web) | Blink | - | Keeps <style> but drops @media queries; clips past ~102KB. |
Gmail (Mobile) | Blink | - | Strips <style> entirely, inline CSS only, no responsive. |
Outlook (Windows) | Word | - | No border-radius, box-shadow, background-image, or media queries; fixed widths. |
Outlook.com | Blink | - | Better than desktop; strips some <style> rules. |
Yahoo Mail | Blink | - | Good support; rewrites some class/id names. |
Real inbox previews#
The switcher above is a simulation. For pictures of the email in the real mail apps, connect a service such as Email on Acid or Litmus. Mailkaro does not run a render farm and does not resell one: you use your own account with the service, and the pictures come from it. With a service connected, Preview gets a Real inbox previews button. Pick the mail apps, run the test, and the pictures arrive one by one (they take from a few seconds to a couple of minutes). Click one to see it larger.
The service's key never reaches the browser. It stays in the code on your server that talks to the service, and the editor only calls your route. With the backend SDK it is three steps:
import { Mailkaro } from "email-craft-sdk";
// EMAILONACID_API_KEY and EMAILONACID_PASSWORD in the environment turn on Email on Acid
const admin = Mailkaro.fromEnv();
// 1. the editor's runtime route already tells the editor the capability is on (capabilities.inboxPreviews)
// 2. one route for the editor to call, next to your /mailkaro/ai route
app.post("/mailkaro/inbox-previews", async (req, res) => {
const { status, body } = await admin.inboxPreviews(req.body);
res.status(status).json(body);
});Another service? Give the SDK a provider with three functions, and the rest is the same. In a page that mounts the editor directly, pass the provider as config.inboxPreviews (or the inboxPreviews prop) instead of using a route:
const admin = new Mailkaro({
serverKey: process.env.MAILKARO_SERVER_KEY!,
inboxPreviews: {
name: "Litmus", // shown to the person
clients: async () => [{ id: "gmail", label: "Gmail", group: "Webmail" }],
start: async ({ html, subject, clients }) => ({ id: await startTest(html, subject, clients) }),
check: async (id) => ({
done: false,
shots: [{ client_id: "gmail", status: "ready", image_url: "https://..." }] // status: pending | ready | failed
})
}
});Programmatic#
The same transform is exported from the renderer:
import { renderDesign, simulateClientHtml, emailClients } from "email-craft-sdk";
const html = renderDesign(design, { fullDocument: true });
const outlookHtml = simulateClientHtml(html, "outlook"); // square corners, no <style>
// emailClients: [{ id, label, engine, width, mobile, notes }]