# Mail and page templates Every mail filex sends and every page it shows somebody who opens a link is a **template** you can change: *Admin → Settings → **Templates***. filex ships one for each; the install's administrator can replace any of them for the whole install, and on a [multi-tenant](MULTI-TENANCY.md) install a tenant's administrator can replace them for their own tenant. **Back to the default** removes your text again. There are two layers, and most installs only need the first: 1. **The theme** - the colours, the logo, the name and the footer line - is the [Branding](CONFIGURATION.md#branding-white-label) page's. Every template wears it: the mails and the pages pick up the accent colour, the logo and the footer text without you touching any HTML. 2. **The templates** - the full HTML and CSS of each mail and page, written in [Liquid](https://shopify.github.io/liquid/), with a live preview and a test mail. This page is about this layer. - [What can be changed](#what-can-be-changed) - [Who edits which templates](#who-edits-which-templates) - [The editor](#the-editor) - [Writing a template](#writing-a-template) - [The public link page](#the-public-link-page) - [An app's public address](#an-apps-public-address) - [Mails](#mails) - [Security](#security) - [API](#api) ## What can be changed | Template | What it is | Its own variables | |---|---|---| | `mail.layout` | The frame of **every** mail: header, logo, footer, the stylesheet. `{{ content }}` is the mail's own part. | `content` | | `mail.share` | A share link sent by mail, or the link an invitation made. | `item.name`, `item.kind` (`file` / `folder`), `item.size`, `item.size_text`, `link.url`, `link.pin`, `link.pin_withheld`, `link.days_left` | | `mail.file_request` | A file request sent by mail. | `folder.name`, `link.url`, `link.pin`, `link.pin_withheld`, `link.days_left`, `limits.max_files`, `limits.max_file_mb`, `limits.types` | | `mail.grant` | An existing account was given access to an item. | `item.path`, `link.url` | | `mail.account` | A new account, with its first password. | `account.email`, `account.password`, `link.url` | | `mail.notification` | Any [notification](NOTIFICATIONS.md) that asks for a mail. | `notice.event`, `notice.title`, `notice.lines`, `link.url` | | `mail.digest` | A notification digest. | `notice.title`, `notice.lines`, `digest.minutes`, `link.url` | | `mail.smtp_test` | The SMTP **Test** button's mail. | - | | `mail.cloud_verify` | The [cloud](CONFIGURATION.md) sign-up code. | `tenant.slug`, `verify.token`, `verify.ttl` | | `mail.app` | A mail an [app](APP-PLUGINS.md) sends: what the app wrote, framed like every other mail. | `app.name`, `message.subject`, `message.body` | | `page.layout` | The frame of every page below: the document, the base stylesheet, the logo and the footer. | `content` | | `page.pin` | A link's PIN gate (shares and file requests). | `form.action`, `form.error`, `link.kind` | | `page.unlocked` | "PIN accepted" before the download starts. | - | | `page.error` | "This link is not available", and the other error pages - also what an [app's public address](#an-apps-public-address) answers when it leads nowhere, after too many tries and when it is unavailable (`error.key` `route_miss`, `route_busy`, `route_unavailable`). | `error.code`, `error.key`, `error.title`, `error.body` | | `page.zip_wait` | "Preparing your download" while a folder's ZIP is built. | `folder.name`, `zip.url` | | `page.folder` | A shared folder, for a browser without JavaScript. | `folder.*`, `entries` (each `name`, `kind`, `url`, `size`, `date`, `thumb`) | | `page.file_request` | A file request's upload page, for a browser without JavaScript. | `folder.name`, `form.name_max` | | `page.app` | An app's link, for a browser without JavaScript. | `app.title`, `files` | | `page.route` | A page an [app's public address](#an-apps-public-address) answers with, such as a short link's `+` preview: the app's words, never its HTML. | `route.title`, `route.text`, `route.link` (a web address, or empty), `route.link_label` | | `page.delete_confirm` | An [uploader](UPLOADERS.md)'s deletion link (`/x/…`): which file, one button. | `file.name`, `form.action` | | `page.delete_done` | The deletion link after the file was deleted. | - | | `page.cache_wait` | "Preparing your download" for a big file on slow storage. | `file.name`, `file.percent` | | `page.shell` | The document the public link page is drawn in ([below](#the-public-link-page)). | `app_head`, `app`, `link.kind` | | `slot.share.title`, `.intro`, `.footer` | Short texts on a share link's page. Empty by default: the page says its own words. | `item.*`, `link.kind`, `link.expires_at`, `link.message` | | `slot.file_request.title`, `.intro`, `.footer` | The same for a file request. | the same | Every template also has `lang`, `dir` (`ltr` / `rtl`), `brand.name`, `brand.logo_url`, `brand.footer_text`, `brand.hide_powered_by`, `theme.accent`, `theme.accent_hover`, `theme.on_accent`, `product.name`, `product.url`, `product.link`, `site.name` and `site.url`; a mail has `mail.subject`, a page `page.title` and `theme.css` (the page's theme and accent stylesheet). The editor lists every variable of the template you have open, and puts one in where the cursor is when you click it. ## Who edits which templates | You are | You edit | Who it reaches | |---|---|---| | The install's administrator (single-tenant, or the platform's own tenant) | the **install's** templates | every mail and page of the install, and every tenant that has not replaced the same template | | A tenant's administrator | **your tenant's** templates | your tenant's mails and the pages of your tenant's links | A tenant's template wins over the install's, the install's over filex's own. Nothing in the API names a tenant: the server reads whose templates you edit from your session, so there is no id to change. Deleting a tenant removes its templates. **Which tenant a public page belongs to.** A page of a **link** - its PIN gate, its folder, its upload page, its ZIP, a deletion link's confirmation, the public link page - wears the templates and the branding of the tenant the link was made in, whatever address it is opened at. A page that belongs to no link, and **every "this link is not available" page**, wears the address's: a visitor learns nothing about whose link a token was from the page that says it is not available. A mail wears the tenant of the link it is about, else the addressee's, else the sender's. The public link page (the application) follows the same rule from its first paint: the document's title, theme colour and icon, the logo, the name and the colours above the card are the link's tenant's (`GET /api/public/{s,d}/{token}/branding`), and a token that names no live link gets the address's. ## The editor ![Admin, Settings, Templates: the mails and pages, the share mail's source in the code editor with a sign-off added, and the preview the server rendered (dark theme)](https://filex.sh/shots/templates/templates-editor-dark-1440.3d00cf3a7359.png) - **The source** is filex's code editor - the one the file preview edits code in (Monaco): Liquid and HTML in colour, line numbers, the usual keyboard (Tab indents, Ctrl+Z, Ctrl+F). When the engine refuses the draft, the line it names is marked in the editor (and scrolled into view), with the engine's words on hover and under the preview. A build of the explorer without Monaco shows a plain text box instead. - **HTML / Subject / Plain text** - a mail has three parts. The plain-text part is optional: left empty, it is made from the HTML (see [Mails](#mails)). - **Variables** - every variable the template has; click one to insert it. The *hooks* line names what the page's own script needs (see [Hooks](#hooks)). - **Preview** - rendered by the server, in the same sandbox the real renders use, with sample data, in the language you pick, and shown in a frame that runs no script. A mail shows its subject and both parts. What the sanitizer had to take out (a `