Email this dashboard's report now (Snowflake native app only).
"Email me this report now" (DVT-4201). Snowflake-native only — 404 outside snowflake mode. Renders the dashboard's KPI/stat tiles and tables inline as HTML and each chart panel as an inline base64 PNG (DVT-4264) with a "View in dvt →" link; no download links. By default (no attachments) it is sent via CALL SYSTEM$SEND_EMAIL(...) executed on the CALLER's own Snowflake session (the same caller's-rights path as POST /v1/data/query), through the consumer's own NOTIFICATION INTEGRATION (see the native-app README's "Enable email reports" step). If the consumer admin opted into the SMTP relay (native app 1.1.1+, DVT-5057), it is instead sent as multipart MIME through the consumer's own mail host, with charts as inline images and an .xlsx attachment per table panel (up to 50 rows; every column of the panel's query result, declared columns first, as Export). On a dashboard with a pinned query role, the email CALLs (smtp_status(), then get_email_integration() + SYSTEM$SEND_EMAIL, or on the relay smtp_relay_send) run under that pinned role instead, which therefore needs the dvt viewer application role (and, pending measurement, CALLER USAGE on the integration — DVT-4345). Requires data:query AND data:export, plus dashboard:read on this dashboard.
Panels that fail to load render as a placeholder with a generic reason (no raw Snowflake error text is ever included in the email body). At most 12 data-bound panels are queried per email — the rest render as "not included" placeholders (counted in panelsOmitted). Tables render up to 50 rows inline, with a "N more rows" link for the remainder. The whole request runs under a 15s panel budget plus a send budget (10s Snowflake, 25s SMTP relay); if no data panel loads in time, or too little of the request window (80s, measured from arrival) is left to start the send, the email is NOT sent and is safe to retry (504 report-timed-out), if every data panel fails for another reason it is NOT sent either (502 report-unavailable), and a send that does not confirm in time returns 504 email-send-unconfirmed — check inboxes before retrying, the mail may still arrive.
Chart images are rendered server-side by dvt-render, at most 12 per email, within a per-email render time budget (charts that have not started rendering when it runs out are noted in place). The dedicated per-org hourly render budget (separate from the export/user render budget, so emailing a report can never rate-limit an export or vice versa) is off by default on the native app (no hourly cap); dvt can set one via EMAIL_RENDER_RATE_LIMIT (a service-template value, not consumer-settable). Charts never fail the send: a chart that cannot be rendered — including one refused because an operator-set hourly budget is spent — is noted in place and counted in panelsFailed, and one that would push the body over the 700 KB budget, that sits past the per-email chart cap, or that was not started because the per-email render time budget ran out, is noted in place and counted in panelsOmitted. Note that Gmail strips data: image URIs and shows the image's alt text instead; Apple Mail, Outlook desktop and iOS Mail render them inline.
params carries the sender's ACTIVE filter state (DVT-4468), so the mail matches the filtered screen rather than the dashboard's default view: every panel that declares a matching key in its data.params is queried with the supplied value, the chart renders receive the same values so the pictures and the tables agree, and the document carries a "Filtered: Region = West" line naming what was applied (also recorded on the dashboard.email audit row as params_applied). Values are BOUND, never interpolated; an undeclared key is a 422 that names it. Omitting params reproduces the pre-DVT-4468 report exactly. A stored SCHEDULE carries no filter state, so an unattended fire still sends the default view.
Async mode (DVT-5096). Send BOTH Prefer: respond-async and an Idempotency-Key header and the request is validated exactly as above, then a background run is recorded and the call answers 202 within about a second with an EmailRun (status queued) instead of waiting for the send. Poll GET /v1/dashboards/{id}/email-runs/{runId} for the result. The run's clock is anchored to request arrival and it must start within the life of the caller's Snowflake session; a session too short-lived to start the send is refused 503 email-async-unavailable with nothing recorded (retry the same request with the same Idempotency-Key). Replaying the same Idempotency-Key returns 200 with the SAME run and never sends a second email — even if the body differs, so mint a new key for every distinct send; the same key for another dashboard is 409. A user may have at most 3 background emails running at once (429). A run whose worker is lost is reported unconfirmed (the mail may have been handed off — check inboxes) or not_attempted (it never started — safe to retry); it is never reported failed unless the send itself definitively failed. With neither header the request is the synchronous call described above, unchanged; with only one of them it is 400.
Request
- Base URL: http://localhost:8080
- URL: http://localhost:8080/v1/dashboards/{id}/email
- Auth: one of:
- API key in cookie dvt_session
- HTTP bearer
Headers
respond-async requests the async mode above; it needs Idempotency-Key too.
1-200 visible ASCII characters, scoped to the calling user. Needed (with Prefer: respond-async) for async mode; a replay returns the original run.
Request body
Response
Async mode only: the Idempotency-Key was already used for this dashboard. Returns the existing run; no new send was started.
Changes
No recorded changes to this operation across all 1 revision of this API.