Preview: SendMock has no stable release yet. These docs follow develop.
SendMock
Mail

Reading and checks

Every tab of an open email, the extracted codes and links, and the quality checks.

Try it in the demo.

Open any email in Mail to see these tabs. They answer "what exactly did my app send?" and "will it look right for the people who get it?".

What it solves

  • An email looks fine in your client but breaks on a phone or in Outlook.
  • A link in the email points at localhost, a wrong domain or a page that does not exist.
  • An attachment or inline image is missing, or the wrong file is attached.
  • A header your provider or the recipient's server needs (List-Unsubscribe, Reply-To) is missing.

The extracted panel

Above the tabs, one-time codes and links found in the email are listed, each with Copy and Open. Codes are found with the patterns in Settings > OTP patterns; add your own if your app's format is not found (Advanced: OTP patterns).

The tabs

TabShowsUse it to
HTMLthe email in a sandboxed frame. Desktop width, Tablet width and Mobile width resize it; Load remote images fetches images from the web (off by default, so opening an email never calls out); Screenshot saves a PNGcheck the layout at each width; attach a screenshot to a bug
Textthe plain-text partcheck people without HTML get a readable email
Sourcethe raw message, highlightedsee exactly what your app sent, byte for byte
Headersevery header as a table, with warnings for a missing or broken List-Unsubscribecheck Reply-To, Message-ID, custom headers
Attachmentseach file with its size and type, image thumbnails, downloadcheck the right file went out
MIMEthe tree of parts: type, encoding, size, download per partdebug inline images (cid:) and multipart problems
Checksclient support for the HTML and CSS used, link and image check results, the spam score (when SpamAssassin is set in Settings > Email), and unsubscribe header checksfix what Outlook or Gmail will not show, broken links, spammy content
Timelinereceived (with a link to the SMTP session or API request), opened, clicked, delivered, bounced, complained, released, replied, forwarded, and each webhook sentfollow everything that happened to this email
Template datafor provider API sends that used a template id: the id and the dynamic datacheck the data your app passed to SendGrid or Postmark templates

Opened events

Opening an email in the UI counts as the recipient opening it: SendMock fires email.opened, which your open tracking can receive through a rule. The header shows "Opened N times" with the history. Turn this off, or fire only on the first open, in Settings > Opened events.

  • First open only (the default): only the first view counts. Viewing the email again changes nothing: no event, and the open count stays the same.
  • Every open: each view fires email.opened with first_open: false and a higher open_count.
  • Simulate open, the API, CLI and MCP always fire, whatever the setting.
  • Mark unread keeps the open count and the first open time.

Each open is kept with its time, its source (ui, manual or api) and the user agent that sent it, if any.

Clicked events

A click on one of an email's links counts as the recipient clicking it, as a provider's click tracking reports it: SendMock fires email.clicked with the link, first_click (the first click on that link), click_count (all clicks on the email), the source and the user agent. The email's Timeline shows each click.

  • A link clicked in the HTML preview opens in a new tab as before, and fires email.clicked with source: "ui". A click is always on purpose, so there is no setting to turn this off.
  • Simulate > Click a link lists the email's links; choosing one fires email.clicked with source: "manual".
  • The API, CLI and MCP fire it for a link you name, which must be one of the email's links; any other URL is refused with unknown_link, since a provider only tracks the links it rewrote.

An email provider's webhook template (SendGrid, Mailgun, Postmark, Resend, Amazon SES, Brevo, SparkPost) sends the click in that provider's own shape, so your app's click handler receives what the real provider would send.

From the CLI, API and AI

On this page