From ff32f28ade72cf17ec6ac74fa274f5c97c71d21e Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski Date: Fri, 25 Sep 2026 12:33:52 +0200 Subject: [PATCH 1/2] docs: email settings and private mail relays A short Email guide: server and company mail settings, sendmail coming from MAIL_SENDMAIL_PATH, and why company owners are held to public mail hosts, with MAIL_ALLOWED_PRIVATE_HOSTS for installs whose owners need a relay on the private network. --- docs/.vitepress/config.ts | 1 + docs/guide/mail.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 docs/guide/mail.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 2e4cc43..4686f83 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -96,6 +96,7 @@ 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: 'AI Assistants (MCP)', link: '/guide/ai-assistants.md' }, { text: 'File Disk', link: '/guide/file-disk.md' }, { text: 'Backups', link: '/guide/backups.md' }, diff --git a/docs/guide/mail.md b/docs/guide/mail.md new file mode 100644 index 0000000..f3ee04b --- /dev/null +++ b/docs/guide/mail.md @@ -0,0 +1,39 @@ +# 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: + +```bash +MAIL_ALLOWED_PRIVATE_HOSTS=mail.lan,192.168.1.10 +``` + +::: warning It names hosts, not an on/off switch +Only the hosts you list, comma separated, become usable by company owners. Every other private address is still refused. The setting is environment-only, so the person who controls the network decides which hosts are trusted, not anyone who can reach a settings page. `GOTENBERG_ALLOWED_PRIVATE_HOST` works the same way for the [PDF renderer](./pdf-generation.md#private-networks-and-the-ssrf-guard). +::: + +The value is matched against the host alone, ignoring capitalisation. List the name or address exactly as it is entered in the mail settings; a name and the address it resolves to are different entries. + +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. From d3b091825eca0dc3871587769f1eaca47df3ca80 Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski Date: Fri, 25 Sep 2026 12:41:57 +0200 Subject: [PATCH 2/2] docs: one page for private network exemptions A Private Networks guide explains why settings that name a host refuse private addresses and lists the per-feature exemptions (GOTENBERG_ALLOWED_PRIVATE_HOST, MAIL_ALLOWED_PRIVATE_HOSTS) and how entries are matched. The Email and PDF guides link to it. --- docs/.vitepress/config.ts | 1 + docs/guide/mail.md | 8 ++------ docs/guide/pdf-generation.md | 2 +- docs/guide/private-networks.md | 26 ++++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 docs/guide/private-networks.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 4686f83..f628284 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -97,6 +97,7 @@ export default defineConfig({ { 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' }, diff --git a/docs/guide/mail.md b/docs/guide/mail.md index f3ee04b..112b856 100644 --- a/docs/guide/mail.md +++ b/docs/guide/mail.md @@ -24,16 +24,12 @@ Saving a private host shows: 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: +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 ``` -::: warning It names hosts, not an on/off switch -Only the hosts you list, comma separated, become usable by company owners. Every other private address is still refused. The setting is environment-only, so the person who controls the network decides which hosts are trusted, not anyone who can reach a settings page. `GOTENBERG_ALLOWED_PRIVATE_HOST` works the same way for the [PDF renderer](./pdf-generation.md#private-networks-and-the-ssrf-guard). -::: - -The value is matched against the host alone, ignoring capitalisation. List the name or address exactly as it is entered in the mail settings; a name and the address it resolves to are different entries. +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. diff --git a/docs/guide/pdf-generation.md b/docs/guide/pdf-generation.md index ad81652..5cc3b82 100644 --- a/docs/guide/pdf-generation.md +++ b/docs/guide/pdf-generation.md @@ -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 diff --git a/docs/guide/private-networks.md b/docs/guide/private-networks.md new file mode 100644 index 0000000..d74d742 --- /dev/null +++ b/docs/guide/private-networks.md @@ -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.