Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const reference: DefaultTheme.SidebarItem[] = [
text: "Features",
collapsed: false,
items: [
{ text: "Web UI", link: "/features/web-ui" },
{ text: "HTML Preview", link: "/features/html-preview" },
{ text: "Webhooks", link: "/features/webhooks" },
{ text: "Email Release", link: "/features/release" },
Expand Down
2 changes: 2 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ Base path: `/api/v1`. All responses are JSON. All IDs are [ULIDs](https://github

The full OpenAPI 3.1 spec is also served at runtime at `GET /api/v1/openapi.yaml`.

`GET /api/v1/info` reports the running server's version and SMTP port, which is handy for checking which build a pipeline is talking to.

<OASpec />
8 changes: 6 additions & 2 deletions docs/features/html-preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

The message detail panel renders the email's HTML body so you see it the way a real client would.

## Desktop and mobile width

When the **Preview** view shows an HTML body, a **Desktop** / **Mobile** switch sits next to it. **Desktop** fills the message pane; **Mobile** renders the email in a 375px wide frame, the width of a phone, so you can check how a responsive template collapses. The choice is kept in the browser and applies to every message.

## Rendering model

The HTML body is rendered inside a **sandboxed iframe** (`sandbox=""`) with a strict `Content-Security-Policy`. This lets RustMail display untrusted email markup without executing any of it:
The HTML body is rendered inside a **sandboxed iframe** (`sandbox="allow-popups allow-popups-to-escape-sandbox"`) with a strict `Content-Security-Policy`. This lets RustMail display untrusted email markup without executing any of it:

| Resource | Policy | Effect |
|----------|--------|--------|
Expand All @@ -14,7 +18,7 @@ The HTML body is rendered inside a **sandboxed iframe** (`sandbox=""`) with a st
| Fonts / objects / frames | `'none'` | No remote fonts, plugins, or nested frames |
| Forms | `form-action 'none'` | Form submissions are blocked |

Because the iframe has no `allow-scripts` or `allow-same-origin`, email content runs in an opaque origin: it cannot read RustMail's cookies, storage, or DOM, and cannot navigate the parent page.
Because the iframe has no `allow-scripts` or `allow-same-origin`, email content runs in an opaque origin: it cannot read RustMail's cookies, storage, or DOM, and cannot navigate the parent page. Links in the email open in a new tab.

## Remote images

Expand Down
60 changes: 60 additions & 0 deletions docs/features/web-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Web UI

The web UI is served on the HTTP port (`8025` by default) and updates live over the [WebSocket](/features/websocket): new mail shows up the moment it arrives.

## Layout

On a window at least 1300px wide the UI has three panes and a status bar:

| Pane | Contents |
|------|----------|
| Inbox | Search, filter chips (**Starred**, **Unread**, **Attachments**, **Tags**), and the message list |
| Message | Subject, sender and recipients, the star, download and delete actions, and the body |
| Details rail | Summary, authentication, attachments, links and headers of the selected message |
| Status bar | Connection, SMTP address, counts, server version and shortcut hints |

The message pane switches between **Preview** (the rendered [HTML body](/features/html-preview)), **Text** and **Raw**.

Below 1300px the details rail becomes a drawer over the message body. Open it with the **Details** button or `i`, and close it with `i` or `Esc`. See [Keyboard Shortcuts](/features/keyboard-shortcuts).

## Theme and palettes

The gear icon in the header opens **Settings**. Under **Appearance**:

- **Theme**: **Dark**, **Light**, or **System** (the default, which follows the operating system).
- **Palette**: **RustMail** (the default), **Ember**, **Copper & Teal**, **Dawn**, or **Classic**. Each palette tints the neutrals and the accent colour, in both themes.

Both choices are kept in the browser's local storage, so they apply per browser rather than per server.

## Details rail

| Section | Contents |
|---------|----------|
| Summary | From, To, date, size, and the message's tags, which you can add and remove here |
| Authentication | DKIM, SPF and DMARC results (see [Email Authentication](/features/email-auth)) |
| Attachments | Each attachment with its size, as a download link |
| Links | Every link in the message (see below) |
| Headers | **Show headers** lists every header the message carries, as received |

### Links

The **Links** section lists every distinct `http`, `https`, `mailto` and `tel` link in the message, in the order they first appear. Links come from the HTML body's anchors and from URLs in the text body. Other schemes, such as `javascript:` or `file:`, are left out.

Each row shows the host and path, the anchor text, and `×N` when the same link appears more than once. Clicking a row opens the link in a new tab; the copy button next to it copies the full URL. The first 8 links are shown, with **Show all** for the rest.

Two badges flag links worth a second look before the mail reaches real users:

| Badge | Meaning |
|-------|---------|
| `HTTP` | Plain `http://`, which mail clients may warn about or block |
| `LOCAL` | Points at loopback (`localhost`, `127.x.x.x`, `[::1]`) or a `.localhost`, `.local` or `.test` name, which recipients cannot reach |

## Status bar

From left to right:

- **Live**, **Connecting** or **Reconnecting**: the state of the WebSocket connection.
- **SMTP** `host:port`: where to send mail, with a copy button. The port comes from [`GET /api/v1/info`](/api/getInfo), so behind Docker or a proxy that remaps ports, the port you reach from outside may differ.
- The message count and how many are unread.
- The server version.
- Hints for the most used shortcuts.
Binary file modified docs/public/screenshot-web.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading