Device previews
Review how email renders across devices and clients before signing off on a send.
Device previews render an email in native email clients and webmail surfaces so a team can approve what recipients will actually see before a campaign, product email, or transactional template goes live.
The API works around a few core objects:
| Object | What it means |
|---|---|
| Native target | A concrete email client and platform, such as ios_mail_physical_device or gmail_android_emulator. Use nativeTargets; the older providers field is deprecated. |
| Preview run | A render job for one email, raw MIME import, HTML import, or render-address submission. |
| Result | The completed run details, target states, and screenshot records. |
| Screenshot | A rendered image for one target. Screenshots can be downloaded through authenticated or shared URLs. |
| Share link | A public tokenized result view that lets reviewers open screenshots without an API key. |
| Render email address | A temporary address that starts a render when an email is sent to it. |
Choose a render workflow
Different teams create device preview runs from different source material. Choose the path that matches where the email exists when you start the review.
| If you have | Use this flow | Why |
|---|---|---|
| A received or sent MailSlurp email | Create a run from the stored emailId |
Best for tests, CI, and email QA already using MailSlurp inboxes. |
A campaign export or .eml fixture |
Import the MIME or upload the .eml file |
Preserves the real headers, body parts, and attachments from an external tool. |
| A template body before it has been sent | Create a run from raw HTML | Fastest way to preview template markup before a full email pipeline exists. |
| A campaign tool, ESP, or manual sender | Send the email to a render address | Lets non-code tools trigger a render by sending email. |
| A one-off manual review | Use the dashboard | Useful for stakeholders who need to inspect screenshots without writing code. |
SDK setup
Create the MailSlurp client once and call device preview operations through mailslurp.devicePreviewsController.
// Read the API key from the environment so examples can run locally and in CI.
const apiKey = process.env.MAILSLURP_API_KEY || process.env.API_KEY;
// Device render methods live on mailslurp.devicePreviewsController.
const mailslurp = new MailSlurp({ apiKey });
Choose native device targets
List device preview targets before creating a run. Use GET /device-preview-targets for the stable catalog of visible native targets. This catalog route is intended for documentation, UI target pickers, and simple runtime discovery, so call it directly with fetch instead of looking for an SDK method.
// The catalog endpoint is public and does not require an API key.
// Use it to build target selectors without tying the list to worker availability.
const response = await fetch("https://api.mailslurp.com/device-preview-targets");
if (!response.ok) {
throw new Error(`Could not load device preview targets: ${response.status}`);
}
const targetCatalog = await response.json();
console.log(targetCatalog);
// Rough shape:
// {
// targets: [
// {
// target: "ios_mail_physical_device",
// client: "Apple Mail",
// platform: "iOS",
// formFactor: "phone",
// engine: "native",
// creditCost: 1,
// timeoutSeconds: 120,
// ...
// }
// ]
// }
Use the availability endpoint only when an authenticated workflow also needs current worker health, queue, or status details.
// List native device targets and their current availability before creating a run.
const nativeTargetAvailability =
await mailslurp.devicePreviewsController.getDevicePreviewNativeTargetAvailability();
console.log(nativeTargetAvailability);
// Rough shape:
// {
// enabled: true,
// heartbeatOfflineAfterSeconds: 60,
// targets: [
// { target: "ios_mail_physical_device", status: "AVAILABLE", enabled: true, ... }
// ]
// }
/emails/device-previews/native-targets/availability
Get native device preview target availability
Returns live native device preview target availability for authenticated API clients, including worker health, queue, timeout, and status fields. Use `/device-preview-targets` when you need the stable catalog without transient availability data.
Request, parameters, and responses
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewNativeTargetAvailabilityListDto | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/native-targets/availability HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/native-targets/availability" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const result = await devicePreviewsController.getDevicePreviewNativeTargetAvailability();
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_native_target_availability()
For examples and quick tests, pick one known native target. Production code can present the catalog to users or store a small target set for each workflow.
// See /docs/device-previews/ for the current device list.
const nativeTarget = "ios_mail_physical_device";
// Use one native target to keep this example focused and quick to run.
const renderOptions = {
nativeTargets: [nativeTarget],
};
Use target IDs exactly as returned by the catalog or availability endpoint. Avoid legacy provider names; a provider can map to more than one native target and no longer describes the render surface precisely enough.
If a request includes an unknown native target, MailSlurp rejects the run request with a client error. Use the stable catalog when building forms or saved target sets, and treat availability as a live health signal rather than the source of truth for what MailSlurp supports.
Available render targets
Use the render target catalog to choose the email clients and device contexts that should be included in a device preview run. The table below is rendered at build time and also tries to refresh from /device-preview-targets in the browser. If the live catalog request fails, the static catalog remains visible.
Device preview target catalog
Current native render targets for email client previews. The static table is refreshed in the browser when the live catalog endpoint is reachable.
| Target | Client | Platform | Surface | Appearance | Timeout | Credits |
|---|---|---|---|---|---|---|
| apple_mail_macos | Apple Mail | macOSdesktop | native app | light | 120s | 1 |
| gmail_android_emulator | Gmail | Androidmobile tablet | native app | light | 180s | 1 |
| gmail_ios_physical_device | Gmail | iOSmobile tablet | native app | light | 180s | 1 |
| gmail_chromium_web | Gmail Web | Chromiumweb | webmail | light | 45s | 1 |
| ios_mail_physical_device | iOS Mail | iOSmobile tablet | native app | light | 180s | 1 |
| ipados_mail_physical_device | iPadOS Mail | iPadOSmobile tablet | native app | light | 180s | 1 |
| outlook_new_windows | New Outlook | Windowsdesktop | native app | light | 150s | 1 |
| outlook_android_emulator | Outlook | Androidmobile tablet | native app | light | 180s | 1 |
| outlook_classic_windows | Outlook Classic | Windowsdesktop | native app | light | 150s | 1 |
| outlook_ios_physical_device | Outlook | iOSmobile tablet | native app | light | 180s | 1 |
| outlook_macos | Outlook | macOSdesktop | native app | light | 120s | 1 |
| outlook_chromium_web | Outlook Web | Chromiumweb | webmail | light | 45s | 1 |
| yahoo_chromium_web | Yahoo Mail | Chromiumweb | webmail | light | 45s | 1 |
Create runs from stored email
Use this path when the message already exists in MailSlurp. It is the most common automation pattern for tests and CI: create or receive the email, store the emailId, and then render that email on the selected native targets.
// Create a temporary inbox and send it HTML so there is a stored email to render.
const existingInbox = await mailslurp.createInboxWithOptions({
expiresIn: 300_000,
name: "device-render-existing-email",
});
await mailslurp.sendEmail(existingInbox.id, {
to: [existingInbox.emailAddress],
subject: "Device render from an existing email",
body: `
<!doctype html>
<html>
<body>
<h1>Device render from an existing email</h1>
<p>This email was sent to a MailSlurp inbox first.</p>
</body>
</html>
`,
isHTML: true,
});
const existingEmail = await mailslurp.waitForLatestEmail(existingInbox.id, 60_000);
// Render the stored email by passing its emailId and native targets.
const existingEmailRun = await mailslurp.devicePreviewsController.createDevicePreviewRun({
emailId: existingEmail.id,
createDevicePreviewOptions: {
nativeTargets: ["ios_mail_physical_device"],
},
});
/emails/{emailId}/device-previews
Create a new device preview run for an email
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
nativeTargets | string[] | No | Optional native mail-client target keys to request for rendering. Null leaves native target selection to ESP configuration. Values are forwarded to ESP so newly deployed ESP targets can be used before this API's enum list is updated. |
{
"nativeTargets": [
"apple_mail_macos"
]
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | CreateDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/00000000-0000-4000-8000-000000000000/device-previews HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"nativeTargets": [
"apple_mail_macos"
]
}
cURL
curl -X POST "https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/device-previews" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"nativeTargets":["apple_mail_macos"]}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"emailId": "00000000-0000-4000-8000-000000000000",
"createDevicePreviewOptions": {
"nativeTargets": [
"apple_mail_macos"
]
}
};
const result = await devicePreviewsController.createDevicePreviewRun(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
create_device_preview_options = {
"nativeTargets": [
"apple_mail_macos"
]
}
result = devicePreviewsController.create_device_preview_run("00000000-0000-4000-8000-000000000000", create_device_preview_options)
If an email might already have an active run, use ensureDevicePreviewRun. It returns the active run when possible and starts a new one only when needed.
// Ensure reuses an active render for the email when possible; otherwise it starts one.
const ensuredExistingEmailRun = await mailslurp.devicePreviewsController.ensureDevicePreviewRun({
emailId: existingEmail.id,
createDevicePreviewOptions: {
nativeTargets: ["ios_mail_physical_device"],
},
});
/emails/{emailId}/device-previews/latest
Return active run for email or create one when none exists
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
nativeTargets | string[] | No | Optional native mail-client target keys to request for rendering. Null leaves native target selection to ESP configuration. Values are forwarded to ESP so newly deployed ESP targets can be used before this API's enum list is updated. |
{
"nativeTargets": [
"apple_mail_macos"
]
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | CreateDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
PUT /emails/00000000-0000-4000-8000-000000000000/device-previews/latest HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"nativeTargets": [
"apple_mail_macos"
]
}
cURL
curl -X PUT "https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/device-previews/latest" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"nativeTargets":["apple_mail_macos"]}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"emailId": "00000000-0000-4000-8000-000000000000",
"createDevicePreviewOptions": {
"nativeTargets": [
"apple_mail_macos"
]
}
};
const result = await devicePreviewsController.ensureDevicePreviewRun(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
create_device_preview_options = {
"nativeTargets": [
"apple_mail_macos"
]
}
result = devicePreviewsController.ensure_device_preview_run("00000000-0000-4000-8000-000000000000", create_device_preview_options)
Create runs from imported email
Imports are useful when the email was produced outside MailSlurp: a campaign platform export, a local build artifact, a customer-supplied .eml, or a fixture generated by a test.
Import into an inbox first
Import the raw RFC822 message into a MailSlurp inbox, then render the imported email by ID. This gives you a durable stored email record as well as the preview run.
// Import a raw RFC822 email into an inbox, then render the imported email.
const importInbox = await mailslurp.createInboxWithOptions({
expiresIn: 300_000,
name: "device-render-inbox-import",
});
const importedRawMime = [
"From: Example Sender <sender@example.test>",
`To: ${importInbox.emailAddress}`,
"Subject: Device render from an inbox import",
`Message-ID: <device-render-inbox-import-${Date.now()}@example.test>`,
"MIME-Version: 1.0",
'Content-Type: text/html; charset="UTF-8"',
"",
"<!doctype html><html><body><h1>Device render from an inbox import</h1></body></html>",
].join("\r\n");
const importedEmail = await mailslurp.inboxController.importEmailIntoInbox({
inboxId: importInbox.id,
importEmailOptions: {
rawEmailBase64: Buffer.from(importedRawMime, "utf8").toString("base64"),
externalId: `inbox-import-${Date.now()}`,
runPipeline: false,
overrideMessageId: true,
},
});
const inboxImportRun = await mailslurp.devicePreviewsController.createDevicePreviewRun({
emailId: importedEmail.id,
createDevicePreviewOptions: {
nativeTargets: ["ios_mail_physical_device"],
},
});
Import base64 raw MIME directly
Use direct import when you already have the full MIME content and do not need to store it in an inbox first.
// Build a complete RFC822/MIME message and base64 encode it for import.
const rawMimeForBase64Import = [
"From: Example Sender <sender@example.test>",
"To: recipient@example.test",
"Subject: Device render from base64 raw MIME",
`Message-ID: <device-render-base64-${Date.now()}@example.test>`,
"MIME-Version: 1.0",
'Content-Type: text/html; charset="UTF-8"',
"",
"<!doctype html><html><body><h1>Device render from base64 raw MIME</h1></body></html>",
].join("\r\n");
const rawMimeImportRun = await mailslurp.devicePreviewsController.createDevicePreviewRunFromImport({
createDevicePreviewImportOptions: {
rawEmailBase64: Buffer.from(rawMimeForBase64Import, "utf8").toString("base64"),
sourceAlias: "raw-mime-base64-example",
externalId: `raw-mime-import-${Date.now()}`,
options: {
nativeTargets: ["ios_mail_physical_device"],
},
},
});
/emails/device-previews/import
Create a device preview run from imported raw MIME
Request, parameters, and responses
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
rawEmailBase64 | string | Yes | Base64 encoded RFC822/MIME email contents. This should be the full raw email including headers and body, such as the bytes from an `.eml` file. |
sourceAlias | string | No | Optional source label to attach to the preview run. |
externalId | string | No | Optional external source ID for correlating this import with another system. |
options | CreateDevicePreviewOptions | No |
{
"rawEmailBase64": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000",
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | CreateDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/import HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"rawEmailBase64": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000",
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/import" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"rawEmailBase64":"user@example.com","sourceAlias":"value","externalId":"00000000-0000-4000-8000-000000000000","options":{"nativeTargets":["apple_mail_macos"]}}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"createDevicePreviewImportOptions": {
"rawEmailBase64": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000",
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
};
const result = await devicePreviewsController.createDevicePreviewRunFromImport(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
create_device_preview_import_options = {
"rawEmailBase64": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000",
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
result = devicePreviewsController.create_device_preview_run_from_import(create_device_preview_import_options)
Upload an EML file
Use multipart import for .eml files from email clients, campaign tools, or fixtures on disk.
// Upload an .eml file as multipart/form-data and create a render from it.
const emlUploadMime = [
"From: Example Sender <sender@example.test>",
"To: recipient@example.test",
"Subject: Device render from EML upload",
`Message-ID: <device-render-eml-upload-${Date.now()}@example.test>`,
"MIME-Version: 1.0",
'Content-Type: text/html; charset="UTF-8"',
"",
"<!doctype html><html><body><h1>Device render from an EML upload</h1></body></html>",
].join("\r\n");
const emlUploadFile = new Blob([emlUploadMime], { type: "message/rfc822" });
emlUploadFile.name = "device-render-example.eml";
const emlUploadRun = await mailslurp.devicePreviewsController.createDevicePreviewRunFromMultipartImport({
file: emlUploadFile,
sourceAlias: "eml-upload-example",
externalId: `eml-upload-${Date.now()}`,
nativeTargets: ["ios_mail_physical_device"],
});
/emails/device-previews/import/multipart
Create a device preview run from multipart EML upload
Request, parameters, and responses
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
sourceAlias | string | No | |
externalId | string | No | |
nativeTargets | string[] | No |
Request body
Responses
| Status | Schema | Description |
|---|---|---|
200 | CreateDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/import/multipart?sourceAlias=value&externalId=00000000-0000-4000-8000-000000000000&nativeTargets=value HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/import/multipart?sourceAlias=value&externalId=00000000-0000-4000-8000-000000000000&nativeTargets=value" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000",
"nativeTargets": [
"value"
]
};
const result = await devicePreviewsController.createDevicePreviewRunFromMultipartImport(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.create_device_preview_run_from_multipart_import(source_alias="value", external_id="00000000-0000-4000-8000-000000000000", native_targets=["value"])
Send raw MIME bytes
Use raw import when the request body should be the RFC822 bytes themselves.
// Send RFC822 bytes directly as the request body for a raw MIME import.
const rawMimeBytes = [
"From: Example Sender <sender@example.test>",
"To: recipient@example.test",
"Subject: Device render from raw MIME bytes",
`Message-ID: <device-render-raw-bytes-${Date.now()}@example.test>`,
"MIME-Version: 1.0",
'Content-Type: text/html; charset="UTF-8"',
"",
"<!doctype html><html><body><h1>Device render from raw MIME bytes</h1></body></html>",
].join("\r\n");
const rawMimeBytesFile = new Blob([rawMimeBytes], { type: "message/rfc822" });
rawMimeBytesFile.name = "device-render-raw-bytes.eml";
// The second argument is RequestInit; its body sends the raw MIME bytes.
const rawMimeBytesRun = await mailslurp.devicePreviewsController.createDevicePreviewRunFromRawImport(
{
sourceAlias: "raw-mime-bytes-example",
externalId: `raw-mime-bytes-${Date.now()}`,
nativeTargets: ["ios_mail_physical_device"],
},
{
body: rawMimeBytesFile,
},
);
/emails/device-previews/import/raw
Create a device preview run from raw MIME bytes
Request, parameters, and responses
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
sourceAlias | string | No | |
externalId | string | No | |
nativeTargets | string[] | No |
Responses
| Status | Schema | Description |
|---|---|---|
200 | CreateDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/import/raw?sourceAlias=value&externalId=00000000-0000-4000-8000-000000000000&nativeTargets=value HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/import/raw?sourceAlias=value&externalId=00000000-0000-4000-8000-000000000000&nativeTargets=value" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000",
"nativeTargets": [
"value"
]
};
const result = await devicePreviewsController.createDevicePreviewRunFromRawImport(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.create_device_preview_run_from_raw_import(source_alias="value", external_id="00000000-0000-4000-8000-000000000000", native_targets=["value"])
Create runs from raw HTML
Raw HTML import is best for template QA before a full email has been sent. Provide a subject, sender, recipient, and HTML body so the renderer can build a realistic message envelope.
// Send HTML directly to the device preview API without first storing an email.
const htmlImportRun = await mailslurp.devicePreviewsController.createDevicePreviewRunFromHtmlImport({
createDevicePreviewHtmlImportOptions: {
html: `
<!doctype html>
<html>
<body>
<h1>Device render from raw HTML</h1>
<p>This render was created directly from an HTML string.</p>
</body>
</html>
`,
subject: "Device render from raw HTML",
from: "Example Sender <sender@example.test>",
to: "recipient@example.test",
sourceAlias: "raw-html-example",
externalId: `html-import-${Date.now()}`,
options: {
nativeTargets: ["ios_mail_physical_device"],
},
},
});
The JavaScript SDK exposes this as createDevicePreviewRunFromHtmlImport. If your generated client does not include the method yet, upgrade the SDK before using HTML imports from code.
/emails/device-previews/import/html
Create a device preview run from HTML
Request, parameters, and responses
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
html | string | Yes | HTML body to wrap into a minimal RFC822/MIME message before creating the device preview run. |
subject | string | No | Optional email subject for the generated MIME. |
from | string | No | Optional From address for the generated MIME. |
to | string | No | Optional To address for the generated MIME. |
sourceAlias | string | No | Optional source label to attach to the preview run. |
externalId | string | No | Optional external source ID for correlating this import with another system. |
options | CreateDevicePreviewOptions | No |
{
"html": "value",
"subject": "Hello from MailSlurp",
"from": "user@example.com",
"to": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | CreateDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/import/html HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"html": "value",
"subject": "Hello from MailSlurp",
"from": "user@example.com",
"to": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000"
}
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/import/html" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"html":"value","subject":"Hello from MailSlurp","from":"user@example.com","to":"user@example.com","sourceAlias":"value","externalId":"00000000-0000-4000-8000-000000000000"}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"createDevicePreviewHtmlImportOptions": {
"html": "value",
"subject": "Hello from MailSlurp",
"from": "user@example.com",
"to": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000"
}
};
const result = await devicePreviewsController.createDevicePreviewRunFromHtmlImport(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
create_device_preview_html_import_options = {
"html": "value",
"subject": "Hello from MailSlurp",
"from": "user@example.com",
"to": "user@example.com",
"sourceAlias": "value",
"externalId": "00000000-0000-4000-8000-000000000000"
}
result = devicePreviewsController.create_device_preview_run_from_html_import(create_device_preview_html_import_options)
Create runs by sending to a render address
A render email address lets any tool start a render by sending an email. This is useful for campaign platforms, QA handoffs, and non-code approval flows.
First create the temporary render address with the native target options you want:
// Create a temporary render email address. Email sent here starts a render run.
const renderEmailAddress = await mailslurp.devicePreviewsController.createDevicePreviewImportAddress({
createDevicePreviewIngestAddressOptions: {
options: {
nativeTargets: ["ios_mail_physical_device"],
},
},
});
/emails/device-previews/import-addresses
Create a temporary email address for device preview import
Request, parameters, and responses
Request body
| Field | Type | Required | Description |
|---|---|---|---|
options | CreateDevicePreviewOptions | No |
{
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewIngestAddressDto | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/import-addresses HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/import-addresses" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"options":{"nativeTargets":["apple_mail_macos"]}}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"createDevicePreviewIngestAddressOptions": {
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
};
const result = await devicePreviewsController.createDevicePreviewImportAddress(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
create_device_preview_ingest_address_options = {
"options": {
"nativeTargets": [
"apple_mail_macos"
]
}
}
result = devicePreviewsController.create_device_preview_import_address(create_device_preview_ingest_address_options)
Use the import-address lookup endpoint if you need to confirm the session details after creating the address.
/emails/device-previews/import-addresses/{sessionId}
Get temporary device preview import address status
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
sessionId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewIngestAddressDto | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/import-addresses/00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/import-addresses/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"sessionId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.getDevicePreviewImportAddress(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_import_address("00000000-0000-4000-8000-000000000000")
Then send an email to the address. The example below sends from a MailSlurp HTTP inbox, but the same address can receive from another mail client or campaign system.
// Send HTML from a MailSlurp HTTP inbox to the render address.
const mailSenderInbox = await mailslurp.createInboxWithOptions({
expiresIn: 300_000,
name: "device-render-mail-sender",
inboxType: "HTTP_INBOX",
});
await mailslurp.sendEmail(mailSenderInbox.id, {
to: [renderEmailAddress.emailAddress],
subject: "Device render through a render email address",
body: `
<!doctype html>
<html>
<body>
<h1>Device render through a render email address</h1>
<p>MailSlurp creates the render run when this email arrives.</p>
</body>
</html>
`,
isHTML: true,
});
Use the email-run and email-submission wait endpoints when an automation needs to watch render-address mail arrive.
/emails/device-previews/email-submissions/wait
Wait for received device preview email submissions
Request, parameters, and responses
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
since | string:date-time | Yes | |
emailDomainId | string:uuid | No | |
profileId | string:uuid | No | |
localPart | string | No | |
limit | integer:int32 | No | |
timeoutMillis | integer:int64 | No | |
pollIntervalMillis | integer:int64 | No |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewEmailSubmissionWaitResult | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/email-submissions/wait?since=value&emailDomainId=00000000-0000-4000-8000-000000000000&profileId=00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/email-submissions/wait?since=value&emailDomainId=00000000-0000-4000-8000-000000000000&profileId=00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"since": "value",
"emailDomainId": "00000000-0000-4000-8000-000000000000",
"profileId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.waitForDevicePreviewEmailSubmissions(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.wait_for_device_preview_email_submissions(since="value", email_domain_id="00000000-0000-4000-8000-000000000000", profile_id="00000000-0000-4000-8000-000000000000")
/emails/device-previews/email-runs/wait
Wait for device preview runs created from account email domains
Request, parameters, and responses
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
since | string:date-time | Yes | |
emailDomainId | string:uuid | No | |
profileId | string:uuid | No | |
localPart | string | No | |
limit | integer:int32 | No | |
timeoutMillis | integer:int64 | No | |
pollIntervalMillis | integer:int64 | No | |
hydrateThumbnail | boolean | No | Hydrate each returned run with a nullable primary screenshot thumbnail URL. |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewIngestRunWaitResult | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/email-runs/wait?since=value&emailDomainId=00000000-0000-4000-8000-000000000000&profileId=00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/email-runs/wait?since=value&emailDomainId=00000000-0000-4000-8000-000000000000&profileId=00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"since": "value",
"emailDomainId": "00000000-0000-4000-8000-000000000000",
"profileId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.waitForDevicePreviewEmailRuns(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.wait_for_device_preview_email_runs(since="value", email_domain_id="00000000-0000-4000-8000-000000000000", profile_id="00000000-0000-4000-8000-000000000000")
Wait for a run
Render work is asynchronous. Start the run, keep the runId, then poll until the run is complete or partially complete. A partial completion can still contain useful screenshots when one target fails or times out.
// Poll until the run completes or the timeout elapses.
const completed = await mailslurp.devicePreviewsController.waitForDevicePreviewRun({
runId,
timeoutMillis: 60_000,
pollIntervalMillis: 2_000,
});
assert.equal(completed.timedOut, false);
assert.match(completed.run.status, /COMPLETE|PARTIAL_COMPLETE/);
/emails/device-previews/{runId}/wait
Wait for device preview run to complete
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
timeoutMillis | integer:int64 | No | |
pollIntervalMillis | integer:int64 | No |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewRunWaitResult | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/00000000-0000-4000-8000-000000000000/wait?timeoutMillis=value&pollIntervalMillis=value HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000/wait?timeoutMillis=value&pollIntervalMillis=value" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000",
"timeoutMillis": null,
"pollIntervalMillis": null
};
const result = await devicePreviewsController.waitForDevicePreviewRun(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.wait_for_device_preview_run("00000000-0000-4000-8000-000000000000", timeout_millis=NaN, poll_interval_millis=NaN)
/emails/device-previews/{runId}
Get device preview run status
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewRunDto | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.getDevicePreviewRun(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_run("00000000-0000-4000-8000-000000000000")
Handle partial, failed, or unwanted runs
Run status tells you whether the overall preview has finished, but target-level status tells you which clients rendered successfully. A partially completed run can still be useful for review, especially when the important target screenshots are present.
Use these operations when a render needs follow-up:
- Rerun selected native targets when a target failed or the template changed only for a small client set.
- Cancel a run that is no longer needed.
- Delete a run when its screenshots should be removed from account history.
- Send feedback when a target screenshot looks wrong or a device client needs investigation.
/emails/device-previews/{runId}/targets/rerun
Rerun selected failed device preview targets in the same run
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
targetIds | string:uuid[] | Yes | Device preview target IDs to rerun within the existing run. Use target IDs from DevicePreviewRunResultsDto.targets. |
failedOnly | boolean | Yes | When true, only selected targets in failed terminal states are rerun. Defaults to true. |
{
"targetIds": [
"00000000-0000-4000-8000-000000000000"
],
"failedOnly": true
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | RerunDevicePreviewTargetsResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/00000000-0000-4000-8000-000000000000/targets/rerun HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"targetIds": [
"00000000-0000-4000-8000-000000000000"
],
"failedOnly": true
}
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000/targets/rerun" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"targetIds":["00000000-0000-4000-8000-000000000000"],"failedOnly":true}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000",
"rerunDevicePreviewTargetsOptions": {
"targetIds": [
"00000000-0000-4000-8000-000000000000"
],
"failedOnly": true
}
};
const result = await devicePreviewsController.rerunDevicePreviewTargets(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
rerun_device_preview_targets_options = {
"targetIds": [
"00000000-0000-4000-8000-000000000000"
],
"failedOnly": True
}
result = devicePreviewsController.rerun_device_preview_targets("00000000-0000-4000-8000-000000000000", rerun_device_preview_targets_options)
/emails/device-previews/{runId}/cancel
Cancel a running device preview run
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No |
{
"reason": "value"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | CancelDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/00000000-0000-4000-8000-000000000000/cancel HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"reason": "value"
}
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000/cancel" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"reason":"value"}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000",
"cancelDevicePreviewRunOptions": {
"reason": "value"
}
};
const result = await devicePreviewsController.cancelDevicePreviewRun(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
cancel_device_preview_run_options = {
"reason": "value"
}
result = devicePreviewsController.cancel_device_preview_run("00000000-0000-4000-8000-000000000000", cancel_device_preview_run_options)
/emails/device-previews/{runId}
Delete local device preview run data
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DeleteDevicePreviewRunResult | OK |
HTTP and SDK snippets
HTTP
DELETE /emails/device-previews/00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X DELETE "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.deleteDevicePreviewRun(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.delete_device_preview_run("00000000-0000-4000-8000-000000000000")
/emails/device-previews/feedback
Create device preview feedback
Request, parameters, and responses
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
source | enum: API_SERVICE | LAB_USER | END_USER | SYSTEM | Yes | |
category | enum: GENERAL | RUN_QUALITY | SCREENSHOT_QUALITY | PROVIDER_ISSUE | BUG_REPORT | FEATURE_REQUEST | Yes | |
status | enum: OPEN | ACKNOWLEDGED | RESOLVED | DISMISSED | No | |
rating | integer:int32 | No | |
runId | string:uuid | No | |
targetId | string:uuid | No | |
screenshotId | string:uuid | No | |
provider | enum: GMAIL | OUTLOOK | YAHOO | No | |
title | string | No | |
comment | string | No | |
internalNote | string | No | |
sessionId | string | No | |
liveViewUrl | string | No | |
metadata | map<string, string> | No |
{
"source": "API_SERVICE",
"category": "GENERAL",
"status": "OPEN",
"rating": 1,
"runId": "00000000-0000-4000-8000-000000000000",
"targetId": "00000000-0000-4000-8000-000000000000"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewFeedbackDto | OK |
HTTP and SDK snippets
HTTP
POST /emails/device-previews/feedback HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"source": "API_SERVICE",
"category": "GENERAL",
"status": "OPEN",
"rating": 1,
"runId": "00000000-0000-4000-8000-000000000000",
"targetId": "00000000-0000-4000-8000-000000000000"
}
cURL
curl -X POST "https://api.mailslurp.com/emails/device-previews/feedback" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"source":"API_SERVICE","category":"GENERAL","status":"OPEN","rating":1,"runId":"00000000-0000-4000-8000-000000000000","targetId":"00000000-0000-4000-8000-000000000000"}'
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"createDevicePreviewFeedbackOptions": {
"source": "API_SERVICE",
"category": "GENERAL",
"status": "OPEN",
"rating": 1,
"runId": "00000000-0000-4000-8000-000000000000",
"targetId": "00000000-0000-4000-8000-000000000000"
}
};
const result = await devicePreviewsController.createDevicePreviewFeedback(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
create_device_preview_feedback_options = {
"source": "API_SERVICE",
"category": "GENERAL",
"status": "OPEN",
"rating": 1,
"runId": "00000000-0000-4000-8000-000000000000",
"targetId": "00000000-0000-4000-8000-000000000000"
}
result = devicePreviewsController.create_device_preview_feedback(create_device_preview_feedback_options)
List and retrieve runs
Use email-scoped listing when you are showing render history for a single stored email. Use account-scoped listing for overview pages, dashboards, or audit tools.
// Fetch one run directly, then list runs by email and account.
const run = await mailslurp.devicePreviewsController.getDevicePreviewRun({
runId,
});
const emailRuns = await mailslurp.devicePreviewsController.getDevicePreviewRuns({
emailId: existingEmail.id,
limit: 10,
hydrateThumbnail: true,
});
const accountRuns = await mailslurp.devicePreviewsController.getDevicePreviewRunsForAccount({
limit: 10,
hydrateThumbnail: true,
});
const paginatedAccountRuns =
await mailslurp.devicePreviewsController.getDevicePreviewRunsForAccountOffsetPaginated({
page: 0,
size: 10,
sort: "DESC",
hydrateThumbnail: true,
});
/emails/{emailId}/device-previews
List previous device preview runs for an email
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer:int32 | No | |
hydrateThumbnail | boolean | No | Hydrate each returned run with a nullable primary screenshot thumbnail URL. |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewRunDto[] | OK |
HTTP and SDK snippets
HTTP
GET /emails/00000000-0000-4000-8000-000000000000/device-previews?limit=value&hydrateThumbnail=true HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/device-previews?limit=value&hydrateThumbnail=true" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"emailId": "00000000-0000-4000-8000-000000000000",
"limit": null,
"hydrateThumbnail": true
};
const result = await devicePreviewsController.getDevicePreviewRuns(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_runs("00000000-0000-4000-8000-000000000000", limit=NaN, hydrate_thumbnail=True)
/emails/device-previews
List previous device preview runs for account
Request, parameters, and responses
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer:int32 | No | |
hydrateThumbnail | boolean | No | Hydrate each returned run with a nullable primary screenshot thumbnail URL. |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewRunDto[] | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews?limit=value&hydrateThumbnail=true HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews?limit=value&hydrateThumbnail=true" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"limit": null,
"hydrateThumbnail": true
};
const result = await devicePreviewsController.getDevicePreviewRunsForAccount(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_runs_for_account(limit=NaN, hydrate_thumbnail=True)
Read results and image URLs
Results include the run, targets, screenshot records, and image URLs. Private screenshot URLs require authentication or a signed S3 URL; public URLs come from a share link.
// Results include targets plus screenshot records with private image URLs.
const results = await mailslurp.devicePreviewsController.getDevicePreviewRunResults({
runId,
});
const imageUrls = results.screenshots
.flatMap((screenshot) => [
screenshot.accessUrl,
screenshot.liveViewUrl,
screenshot.deepLinkUrl,
])
.filter(Boolean);
console.log(imageUrls);
/emails/device-previews/{runId}/results
Get device preview run results
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewRunResultsDto | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/00000000-0000-4000-8000-000000000000/results HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000/results" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.getDevicePreviewRunResults(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_run_results("00000000-0000-4000-8000-000000000000")
Download screenshot images
Download private screenshots through the authenticated API when your app needs to store evidence, attach results to a report, or compare images in a test workflow.
// Download a private screenshot image through the authenticated API.
const screenshotImage = await mailslurp.devicePreviewsController.getDevicePreviewRunScreenshot({
runId,
screenshotId: primaryScreenshot.screenshotId,
});
/emails/device-previews/{runId}/screenshots/{screenshotId}/image
Get a device preview screenshot image
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes | |
screenshotId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | string:byte | OK |
HTTP and SDK snippets
HTTP
GET /emails/device-previews/00000000-0000-4000-8000-000000000000/screenshots/00000000-0000-4000-8000-000000000000/image HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/emails/device-previews/00000000-0000-4000-8000-000000000000/screenshots/00000000-0000-4000-8000-000000000000/image" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, DevicePreviewsControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const devicePreviewsController = new DevicePreviewsControllerApi(config);
const request = {
"runId": "00000000-0000-4000-8000-000000000000",
"screenshotId": "00000000-0000-4000-8000-000000000000"
};
const result = await devicePreviewsController.getDevicePreviewRunScreenshot(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.device_previews_controller_api import DevicePreviewsControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
devicePreviewsController = DevicePreviewsControllerApi(api_client)
result = devicePreviewsController.get_device_preview_run_screenshot("00000000-0000-4000-8000-000000000000", "00000000-0000-4000-8000-000000000000")
Share results publicly
Create a share link when reviewers need a browser-friendly result page without using an API key. Shared results expose public image URLs and can be revoked later.
// Create a share link, then read public image URLs from the shared result.
const shareLink = await mailslurp.devicePreviewsController.createDevicePreviewShareLink({
runId,
createDevicePreviewShareLinkOptions: {
label: "Device render example share link",
},
});
const shareLinks = await mailslurp.devicePreviewsController.getDevicePreviewShareLinks({
runId,
});
const sharedResult = await mailslurp.devicePreviewsController.getDevicePreviewSharedResult({
shareToken: shareLink.token,
});
const publicImageUrls = sharedResult.screenshots
.map((screenshot) => screenshot.imageUrl)
.filter(Boolean);
const publicScreenshotImage =
await mailslurp.devicePreviewsController.getDevicePreviewSharedResultScreenshot({
shareToken: shareLink.token,
screenshotId: sharedResult.screenshots[0].screenshotId,
});
List existing share links before creating a new approval link for the same run. This helps dashboards avoid creating duplicate public links for the same review.
/emails/device-previews/{runId}/share-links
List share links for a device preview run
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewShareLinkDto[] | OK |
HTTP and SDK snippets
/emails/device-previews/{runId}/share-links
Create a share link for a device preview run
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
runId | string:uuid | Yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
label | string | No | |
expiresAt | string:date-time | No |
{
"label": "value",
"expiresAt": "2026-06-21T00:00:00.000Z"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewShareLinkDto | OK |
HTTP and SDK snippets
/emails/device-previews/share/{shareToken}
Get a public shared device preview result
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
shareToken | string | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DevicePreviewSharedResultDto | OK |
HTTP and SDK snippets
/emails/device-previews/share/{shareToken}/screenshots/{screenshotId}/image
Get a public shared device preview screenshot image
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
shareToken | string | Yes | |
screenshotId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | string:byte | OK |
HTTP and SDK snippets
/emails/device-previews/share-links/{shareLinkId}
Revoke a device preview share link
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
shareLinkId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DeleteDevicePreviewShareLinkResult | OK |
HTTP and SDK snippets
Compare with previous runs
Device previews are most useful when you can compare the current render against an earlier approved version. MailSlurp stores run history, so you can use an earlier run as a baseline and review the new screenshots beside it.
For manual review, open the current and previous result pages or share links and compare the same native target in each run. Focus on layout shifts, missing images, CTA visibility, dark-mode changes, and client-specific spacing differences.
For automated comparison:
- Track the approved baseline run ID in your app, or list previous runs for the same stored email.
- Fetch results for the baseline run and the current run.
- Match target results by native target ID.
- Download the private screenshots, or use public screenshot URLs from share links.
- Compare the image files in your visual regression tool, then store the current run ID as the next baseline when approved.
Use share links when product, marketing, legal, or customer stakeholders need to compare results without an API key. Revoke a share link after approval if the screenshots should no longer be public.
Trigger device renders from the dashboard
Use the dashboard when you are reviewing a single message, checking a template manually, or giving stakeholders a visual approval path.
flowchart LR
emailViewer["Dashboard email view"] --> mailslurp["MailSlurp"]
ingestAddress["Render email address"] --> mailslurp
emlImport["EML import"] --> mailslurp
htmlUpload["HTML upload"] --> mailslurp
apiRequest["API calls"] --> mailslurp
mailslurp --> deviceGrid["Device and client grid"]
deviceGrid --> desktop["Desktop previews"]
deviceGrid --> mobile["Mobile previews"]
deviceGrid --> webmail["Webmail previews"]
deviceGrid --> evidence["Shareable render results"]From the MailSlurp email viewer
Use this path when the email already exists in MailSlurp.
- Create a new MailSlurp inbox, or open an existing inbox.
- Send the email you want to review to that inbox.
- Open the received email in the MailSlurp dashboard.
- Click View in Mail Clients to choose render targets and start the preview run.

Import an exported email
Use direct import when you have an exported .eml or RFC 822 email file. This is useful for messages produced by another mail client, a campaign platform, or an internal build step.
- Export or download the email as an
.emlfile. - Open Device previews in the MailSlurp dashboard.
- Click Import .eml.
- Upload the file, choose render targets, and start the preview.


Upload HTML
Use HTML upload when you want to preview a template body before it is sent as a complete email. This is useful for design reviews, template QA, or quick checks from a build artifact.
- Open Device previews in the MailSlurp dashboard.
- Choose the HTML upload option.
- Paste or upload the HTML body.
- Select render targets and start the preview.
Send to a device render email address
Each account can use a specially assigned address under emailondevice.com. Send an email to that address from any client or campaign tool and MailSlurp starts a device render automatically.
The address has three parts:
marketing@acme.emailondevice.com
|-------| |--| |-----------------|
profile subdomain render domain
- The local part is the profile, such as
marketing,qa, orall. - The subdomain is assigned to your account and can be changed to match your organization if the name is available.
- The domain is
emailondevice.com.
Profiles let you create named target sets for projects, teams, or campaigns. Sending to any local part at your subdomain still starts a render using the default target set, so a missed or new profile name does not block the review.

What to review
Focus on the things that break real launches:
- layout shifts between clients
- image scaling and spacing problems
- CTA visibility and tap targets on mobile
- typography or fallback styling differences
- dark or light client behavior if relevant to your audience
Device previews answer "does the email look right in this client?" They do not answer every deliverability question. If you want to know whether a message is likely to land in spam, whether real mailbox providers accepted it, or whether sender reputation is at risk, pair visual rendering with the deliverability features below.
Check inbox placement and blocklists
Use Deliverability tests when you need inbox placement checks, spam-folder signals, and pass/fail release gates across a selected cohort. The Inbox placement and deliverability tests product page explains the broader workflow for checking whether emails reach inboxes or spam folders before a launch.
Use Domain Monitor when you need to watch sender-domain health over time, including SPF, DKIM, DMARC, MX, and DNS drift. For a direct blocklist-style check, use the email blacklist checker alongside Domain Monitor so rendering, placement, and sender reputation are all covered.
Review results
Open the results grid to compare each client render, then open any screenshot to review the full image and download it for approval.


Result notifications
Device render notifications can send progress and completion messages to Slack or Microsoft Teams. Completion messages can include a link to a shareable result page so reviewers can open the rendered screenshots without needing to search the dashboard.
Typical render notification events include:
- render started
- render completed
- render failed
- render partially completed
Set up render notifications
Open Device preview notifications in the MailSlurp dashboard to connect Slack or Microsoft Teams, choose where messages should be sent, and send a test notification before using the rule for production reviews.
Slack render notifications
Use Slack when render reviews happen in a Slack channel.
- Open Configure Slack from the render notifications page.
- Approve the MailSlurp Notifications app in Slack.
- Return to MailSlurp, load channels, and add the channel to notify.
- Create a notification rule and send a test notification.


Microsoft Teams render notifications
Use Microsoft Teams when render reviews happen in a Teams chat or channel.
- Open Configure Teams from the render notifications page.
- Sign in with a Microsoft work or school account if Teams asks.
- Press Send on the prefilled MailSlurp connect message in Teams.
- Return to MailSlurp, wait for confirmation, then create a notification rule and send a test notification.

Recommended review flow
- Render the message in the native targets that matter most.
- Check the hero, CTA, body copy, footer, and any legally required content.
- Fix the template or content if a high-impact rendering issue appears.
- Create a share link for approval evidence.
- Pair the visual review with Email audit when links and images also need validation.