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
2 changes: 2 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export default defineConfig({
{ text: 'Custom Fields', link: '/guide/custom-fields.md' },
{ text: 'Custom Templates', link: '/guide/custom-templates.md' },
{ text: 'PDF Generation', link: '/guide/pdf-generation.md' },
{ text: 'Email', link: '/guide/mail.md' },
{ text: 'Private Networks', link: '/guide/private-networks.md' },
{ text: 'AI Assistants (MCP)', link: '/guide/ai-assistants.md' },
{ text: 'File Disk', link: '/guide/file-disk.md' },
{ text: 'Backups', link: '/guide/backups.md' },
Expand Down
35 changes: 35 additions & 0 deletions docs/guide/mail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Email

InvoiceShelf sends invoices, estimates, payment receipts and customer statements by email. It uses one of these transports: SMTP, sendmail, PHP's `mail`, Amazon SES, Mailgun or Postmark.

There are two levels of mail settings:

- **Server mail**, under **Administration → Settings → Mail Configuration**. Only the super admin can change it, and every company uses it by default.
- **Company mail**, under **Settings → Mail Configuration** in a company. A company owner can switch on a custom configuration, and that company then sends through its own transport and sender address.

## Sendmail

The sendmail command comes from the server, never from a settings screen. Set it with `MAIL_SENDMAIL_PATH` (default `/usr/sbin/sendmail -bs -i`); the mail settings only choose sendmail as the transport.

## Private networks

A company's mail settings could otherwise be used to make the server connect to internal services. So company owners, other than the super admin, may only use publicly reachable hosts:

- the SMTP host, and the host inside an SMTP URL, must not be a private, loopback, link-local or other reserved address;
- the Mailgun endpoint must be `api.mailgun.net` or `api.eu.mailgun.net`.

Saving a private host shows:

> The mail host must be a publicly reachable host, not a private or reserved address.

The super admin is not held to this. A relay on the local network, such as a Postfix container or an on-premises Exchange server, is an ordinary setup for the person who runs the server.

If company owners need a relay on your network and you accept that risk, name it in the environment, comma separated:

```bash
MAIL_ALLOWED_PRIVATE_HOSTS=mail.lan,192.168.1.10
```

Only those hosts become usable by company owners; every other private address is still refused. How entries are matched, and the equivalent setting for Gotenberg, are on the [Private Networks](./private-networks.md) page.

A private host saved by a company owner before this rule existed is refused when they send a test mail. Save a public host, or name the relay as above.
2 changes: 1 addition & 1 deletion docs/guide/pdf-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Only the exact value you set here is exempt. Pointing the Gotenberg host at any
This is also why the setting is environment-only and absent from the admin UI: the person who decides a private host is trustworthy should be the person who controls the network, not anyone who can reach a settings page.
:::

The value must match what you enter as the Gotenberg host, though comparison ignores capitalisation and a trailing slash. If the two differ in any other way — a different port, `https` instead of `http`, a path — the exemption does not apply.
The value must match what you enter as the Gotenberg host, though comparison ignores capitalisation and a trailing slash. If the two differ in any other way — a different port, `https` instead of `http`, a path — the exemption does not apply. The other features with a private-network exemption are listed on the [Private Networks](./private-networks.md) page.

## Troubleshooting

Expand Down
26 changes: 26 additions & 0 deletions docs/guide/private-networks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Private Networks

Some settings name a host that the server connects to: the Gotenberg PDF renderer, a company's mail server, an exchange-rate provider, an S3-compatible storage endpoint. InvoiceShelf refuses private, loopback, link-local and other reserved addresses in those settings. Otherwise anyone who can reach the settings screen could aim the server at services that are only meant to be reachable from inside your network, such as a database admin panel or a cloud provider's metadata endpoint.

When a setting is refused, the message says the host "must be a publicly reachable" address.

## Naming a trusted host

Some features legitimately talk to a host on your own network: Gotenberg usually runs as a sidecar container, and some installs relay mail through an internal server. For those, the operator names the trusted host in the environment, per feature:

| Variable | Feature | What it names | Example |
|---|---|---|---|
| `GOTENBERG_ALLOWED_PRIVATE_HOST` | [PDF generation](./pdf-generation.md#private-networks-and-the-ssrf-guard) | Exactly one Gotenberg URL | `http://pdf:3000` |
| `MAIL_ALLOWED_PRIVATE_HOSTS` | [Email](./mail.md#private-networks), for company owners | Mail hosts, comma separated | `mail.lan,192.168.1.10` |

Restart the app after changing them.

::: warning Hosts, not an on/off switch
Only what you list is exempt, and only for that feature. Every other private address stays refused, and naming your mail relay does not let the PDF setting reach it. There is deliberately no setting that turns the check off, and none of this is editable from the admin screens: the person who controls the network decides which hosts are trusted, not anyone who can reach a settings page.
:::

## How entries are matched

- An entry with a scheme, such as `http://pdf:3000`, exempts exactly that URL. Capitalisation and a trailing slash are ignored; a different port, `https` instead of `http`, or a path is a different URL.
- An entry without a scheme, such as `mail.lan`, exempts that host wherever it appears, as a bare host or inside a URL like `smtp://user:secret@mail.lan:25`.
- A name and the address it resolves to are separate entries. List the value exactly as it is entered in the setting.
Loading