Shared Mailboxes
Shared Mailboxes
Admin path: Email Server > Shared Mailboxes (view_shared_mailboxes.cfm,
inc/shared_mailbox_actions.cfm, inc/sync_shared_mailbox_acl_file.cfm,
inc/sync_user_folder_acl_file.cfm, inc/get_shared_mailbox_permissions_json.cfm).
This page manages mailboxes that several users can read from and
write to — typically role addresses like info@, support@, or
sales@. A shared mailbox is a real Dovecot mailbox in its own
Maildir, but it has no login of its own; users access it through
their own credentials and the rights granted on this page. The
master switch for the entire shared-mailbox feature lives on
Email Server > Settings (Mailbox Sharing card) — when
that switch is off, the rows on this page are preserved but inactive,
and the Add / Manage Permissions / Rebuild buttons are disabled.
Per-member rights are stored in the shared_mailbox_permissions
table and projected to Dovecot's on-disk dovecot-acl files via the
vfile driver, which is the only per-mailbox ACL driver shipped with
Dovecot 2.4 (the SQL rights driver was a non-upstream Hermes carry
that was removed in the 2.4 rewrite).
How a shared mailbox is wired
| Component | Storage | Role |
|---|---|---|
| Mailbox row | mailboxes with mailbox_type = 'shared' |
Gives Dovecot a userdb entry so the mailbox has a quota, a Maildir, and a sender identity |
| Shared mailbox row | shared_mailboxes |
UI metadata: address, display name, auto-subscribe flag, owning domain |
| Per-member rights | shared_mailbox_permissions |
Authoritative permission matrix per (shared mailbox, user mailbox) pair |
| On-disk ACL | /srv/mail/<domain>/<local>/dovecot-acl |
Dovecot vfile driver enforcement file — projected from shared_mailbox_permissions |
| Shared namespace visibility | dovecot_acl_shared (acl_sharing_map) |
Tells Dovecot's Shared/ namespace which users should see this mailbox in their folder list |
| Recipient policy | recipients (Amavis SVF policy + recipient_type = 'shared') |
Allows mail addressed to the shared address to pass the Amavis recipient gate |
| Sender identity | sender_login_maps |
Lets the shared address be used as a From: by itself (anchor row) and by each member with Send-As granted |
| Maildir | /srv/mail/<domain>/<local>/ |
The actual on-disk message store. Bootstrapped via doveadm mailbox create -u <addr> INBOX so members see it immediately rather than waiting for first delivery |
The add handler creates all of these in a single cftry block. If
any step fails the catch sets session.m = 30 and the operation
fails-loud rather than leaving a partial mailbox.
Permission model — seven flags, projected to IMAP ACL letters
The UI surfaces seven permission flags. Six are IMAP ACL rights enforced by Dovecot; one (Send-As) is a Postfix sender-identity grant.
| UI flag | DB column | Dovecot vfile rights | IMAP ACL meaning |
|---|---|---|---|
| Read | can_read |
lrs |
lookup (see mailbox), read (read messages), write-seen (set/clear \Seen flag) |
| Write | can_write |
wt |
write (set/clear flags except \Seen and \Deleted), write-deleted (set/clear \Deleted) |
| Delete | can_delete |
e |
expunge (permanently remove messages) |
| Insert | can_insert |
i |
insert (append/copy messages into mailbox) |
| Post | can_post |
p |
post (submit messages via the post address — rarely used) |
| Admin | can_admin |
a |
admin (modify the ACL itself from an IMAP client) |
| Send-As | send_as |
— | Inserts (sender = shared, login_user = member) into sender_login_maps so the member can use the shared address as From: |
The vfile letters are concatenated into a single token per user
(e.g., lrswtie for read+write+delete+insert). Dovecot 2.4's vfile
parser reads each character as a separate right, so the full-word
form (lookup read write-seen ...) does NOT work — the parser would
treat o in lookup as an unknown right. The
sync_shared_mailbox_acl_file.cfm include knows this and emits the
single-letter form.
The dovecot_acl SQL table is still written by the action handlers
for legacy/audit reasons, but Dovecot 2.4 no longer reads it.
sync_shared_mailbox_acl_file.cfm writes the on-disk file every time
permissions change, and the Rebuild ACL Files button on the page
regenerates every file from scratch — used after upgrading to a new
Dovecot release or when an admin reports a member can't see a
mailbox they should have rights on.
How a save propagates
Add Shared Mailbox ──► shared_mailbox_actions.cfm (add_shared_mailbox)
│
│ 1. Feature guard (Mailbox Sharing = enabled)
│ 2. Validate prefix + domain + display name + quota
│ 3. Four-way conflict check
│ (recipients, mailboxes, mailbox_aliases,
│ virtual_recipients)
│ 4. INSERT into recipients (Amavis SVF policy)
│ + maddr (Amavis address tracking)
│ 5. INSERT into mailboxes (mailbox_type='shared')
│ 6. INSERT into shared_mailboxes
│ 7. INSERT into sender_login_maps (anchor row)
│ 8. docker exec hermes_dovecot doveadm mailbox
│ create -u <addr> INBOX (bootstrap Maildir)
│ 9. For each initial member:
│ - INSERT shared_mailbox_permissions
│ - INSERT dovecot_acl (legacy)
│ - INSERT dovecot_acl_shared (namespace)
│ - INSERT sender_login_maps if Send-As
│ 10. cfinclude sync_shared_mailbox_acl_file.cfm
│ → writes /srv/mail/<dom>/<local>/dovecot-acl
│ via temp shell script + docker exec -i
│ (heredoc pattern; vmail:vmail 0660)
v
cflocation → session.m = 1
Add / Edit / Remove permission flows follow the same shape but only
touch the rows for one member, then re-call
sync_shared_mailbox_acl_file.cfm to rebuild that mailbox's
dovecot-acl file in place. The sync include uses the temp shell
script + heredoc + docker exec -i pattern (it has to — Lucee
cfexecute argument quoting can't reliably ship multiline content
with embedded special characters through docker exec).
Cards and modals on the page
Add Shared Mailbox modal
| Field | Notes |
|---|---|
| Domain | Dropdown of mailbox-type domains (domains.type = 'mailbox'). The Address Prefix suffix updates live to show the full address. |
| Address Prefix | Local-part of the email. Validated against ^[a-z0-9._-]+$ — only lowercase letters, digits, dots, hyphens, underscores. |
| Display Name | Free-form text shown as the mailbox's name and in the table. Required. |
| Quota (GB) | Mailbox quota. Accepts decimals (e.g., 0.5). Stored as bytes via Round(quota_gb * 1024^3). |
| Auto-Subscribe | When Yes (default), the shared mailbox appears automatically in each member's IMAP folder list. When No, members have to manually subscribe to Shared/<address> in their client. |
| Initial Members | Checkbox list of user mailboxes in the selected domain (filtered live as the Domain dropdown changes). Optional — you can grant access later. |
| Default Permissions | Seven checkboxes applied uniformly to every selected initial member. Defaults are Read + Write + Insert checked. |
The address-prefix suffix and the member-list filter both run client-side when the Domain dropdown changes. Cross-domain members are excluded from the picker even before form submit; the server-side handler re-enforces the same-domain rule with error 26 if a forged post tries to bypass it.
Shared Mailboxes table
DataTables surface — searchable, sortable, paginated, stateSave: true.
| Column | Source |
|---|---|
| Actions | Manage Permissions (opens modal) / Delete (opens confirmation modal) |
| Address | shared_mailboxes.address |
| Display Name | shared_mailboxes.display_name |
| Domain | domains.domain |
| Members | Count of shared_mailbox_permissions rows for this shared mailbox |
| Quota | mailboxes.quota divided into GB (1-decimal for whole GB, 2-decimal otherwise) |
| Auto-Subscribe | YES / NO badge |
| Status | Active (sharing on + mailbox active) / Inactive (sharing on + mailbox disabled) / Inactive (Sharing Off) (master switch off) |
A Domain filter dropdown narrows the visible rows to one domain.
Manage Permissions modal
Opens via the per-row action button. Two sections:
- Current Members — table of every
shared_mailbox_permissionsrow for this shared mailbox, with per-right YES/NO badges and Edit / Remove buttons per row. Loaded via AJAX fromget_shared_mailbox_permissions_json.cfm. - Add Member — Tom Select user picker (filtered to the same
domain as the shared mailbox) + the seven permission checkboxes
- an Add button.
The Edit Member sub-modal opens on top of the Manage Permissions modal, lets you toggle the seven flags for an existing member, and re-syncs the on-disk ACL file on save. Changes take effect immediately; the member does not need to reconnect their mail client.
Rebuild ACL Files modal
A maintenance action that walks both admin-managed shared
mailboxes AND user-managed folder shares and regenerates every
dovecot-acl file from the current state of the database.
When to use Rebuild ACL Files.
- After upgrading to a new Dovecot 2.4 release — backfills the vfile files for any shared mailboxes created before the upgrade.
- When a member reports they cannot see or access a shared mailbox or shared folder they should have rights on (recovery / drift heal).
- After manually editing
shared_mailbox_permissionsoruser_folder_sharesin the database.Safe to run anytime — it rebuilds files from the database and never modifies the permission rows themselves. Per-mailbox failures are non-fatal; the operation continues to the next.
Delete Shared Mailbox modal
A confirmation modal that lists exactly what will be removed:
- All member permissions and ACL entries
- Sender login maps (send-as permissions)
- Dovecot shared folder subscriptions
- Amavis policy entry
With an optional Also delete all email messages from the server
checkbox (default checked) that, when set, runs
docker exec hermes_dovecot rm -rf /srv/mail/<domain>/<local> to
remove the Maildir. The DB rows are deleted regardless of that
checkbox; only the on-disk messages are conditional. Maildir deletion
is wrapped in a non-fatal cftry — failure leaves the messages on
disk for an admin to clean up later, but the DB state is correct.
User-initiated folder shares — same engine, different page
Individual users can share folders from their own mailbox with other
users via the User Portal (/users/2/), and those shares land in
user_folder_shares rather than shared_mailbox_permissions. They
are projected to dovecot-acl files by sync_user_folder_acl_file.cfm
using the same vfile driver. The Rebuild ACL Files button on
this page rebuilds both types of share in one pass, so admins don't
have to think about the distinction when troubleshooting.
| Admin-managed shared mailbox | User-initiated folder share | |
|---|---|---|
| Surface | This page | User Portal > Folder Sharing |
| Storage | shared_mailboxes + shared_mailbox_permissions |
user_folder_shares |
| Underlying mailbox | A dedicated mailboxes row with mailbox_type='shared' |
The owner's existing mailbox + a named folder path |
| Visibility namespace | Shared/<address>/INBOX |
Shared/<owner>/<folder_path> |
| ACL file path | /srv/mail/<dom>/<local>/dovecot-acl |
/srv/mail/<owner-dom>/<owner-local>/<folder>/dovecot-acl |
| Cleanup on member removal | This page's Remove Permission | Owner removes the share from User Portal |
Cross-domain members — not supported, enforced server-side
Nextcloud Mail caches the folder tree per account
Nextcloud Mail (the NC webmail app) caches each connected account's IMAP folder tree the first time the account is added and refreshes it lazily. A user who is newly granted access to a shared mailbox via this page will NOT see it in Nextcloud Mail until they remove and re-add their NC mail account. Standalone IMAP clients (Thunderbird, Outlook, Apple Mail) refresh the folder tree on the next IDLE cycle or manual sync, so they don't have this gotcha.
This is upstream NC Mail behavior, not a Hermes setting. The workaround is documented for end-users in the User Portal documentation; for admins, the remediation is to tell the affected user to re-add their NC mail account once the share is in place.
Feature-disabled behavior
When the Mailbox Sharing master switch on Settings is off:
- The Add / Rebuild / Manage Permissions buttons render disabled with a tooltip pointing back to Settings.
- An amber banner at the top of the page explains the state and links to Settings.
- Existing shared mailboxes appear in the table with status badge
Inactive (Sharing Off)so the admin can see what would resume when the switch is flipped back on. - The Delete button still works — admins can clean up rows while the feature is off.
- The
add_shared_mailbox,add_permission,edit_permission, andsync_all_acl_filesaction handlers all check the master switch at entry and return error 31 if it's off, so a stale tab can't silently bypass the guard.
Dovecot itself does not declare the Shared/ namespace when the
master switch is off, so IMAP clients won't see shared folders even
if the on-disk ACL files exist. Existing ACL files are preserved and
re-activate as soon as the switch is flipped back on.
Failure semantics
| What breaks | What happens |
|---|---|
| Master switch off + Add / Edit / Sync attempted | error 31, no DB write |
| Blank address prefix | error 10 |
| Address prefix has invalid characters | error 11 |
| Domain missing or not mailbox-type | error 12 |
| Address collides with mailbox / alias / virtual recipient / existing shared mailbox | error 13 |
Quota not numeric or <= 0 |
error 14 |
| Blank display name | error 15 |
| Stale shared_mailbox_id (deleted between page load and submit) | error 21 |
| Invalid user_mailbox_id | error 22 |
| User already has permissions on this shared mailbox | error 23 |
| Stale permission_id (Edit / Remove) | error 24 |
| Add / Edit Permission with all seven flags off | error 25 |
| Cross-domain member attempt | error 26 |
| Any database operation throws inside the cftry | error 30, no rows committed |
doveadm mailbox create fails |
non-fatal — Maildir bootstraps via LMTP on first delivery instead |
sync_shared_mailbox_acl_file.cfm fails |
non-fatal — DB is the source of truth; the next permission change retries the sync, or admin can use Rebuild ACL Files |
Maildir rm -rf on delete fails |
non-fatal — DB rows are removed regardless; admin can manually clean up /srv/mail/<domain>/<local> |
Files and containers touched
| Path | Owner | Role |
|---|---|---|
config/hermes/var/www/html/admin/2/view_shared_mailboxes.cfm |
hermes_commandbox |
Page + table + Add / Manage / Delete / Rebuild modals |
config/hermes/var/www/html/admin/2/inc/shared_mailbox_actions.cfm |
hermes_commandbox |
Dispatcher for all six actions (add / delete / add_permission / edit_permission / remove_permission / sync_all_acl_files) |
config/hermes/var/www/html/admin/2/inc/sync_shared_mailbox_acl_file.cfm |
hermes_commandbox |
Rebuilds one dovecot-acl file from shared_mailbox_permissions |
config/hermes/var/www/html/admin/2/inc/sync_user_folder_acl_file.cfm |
hermes_commandbox |
Same engine for user-initiated folder shares |
config/hermes/var/www/html/admin/2/inc/get_shared_mailbox_permissions_json.cfm |
hermes_commandbox |
AJAX endpoint for the Manage Permissions table |
/srv/mail/<domain>/<local>/dovecot-acl |
hermes_dovecot (vmail:vmail 0660) |
Per-mailbox vfile ACL file — Dovecot 2.4's enforcement source |
/srv/mail/<domain>/<local>/ |
hermes_dovecot |
The Maildir itself |
/opt/hermes/tmp/<token>_sync_shared_acl.sh |
hermes_commandbox |
Throwaway shell script used to ship the ACL payload through docker exec -i via heredoc |
shared_mailboxes, shared_mailbox_permissions, user_folder_shares, mailboxes, recipients, maddr, sender_login_maps, dovecot_acl, dovecot_acl_shared, parameters2 |
hermes_db_server |
Storage |
hermes_dovecot container |
— | doveadm mailbox create (bootstrap), rm -rf (delete), and the in-container mkdir / cat / chown / chmod invoked by the sync helper |
Related
- Settings — the Mailbox Sharing master switch. Must be on for shared mailboxes to actually function at the IMAP layer. Also the Dovecot TLS profile and connection limits that all shared-mailbox access goes through.
- Mailboxes — the user mailbox list. Members granted permission on this page must already exist there.
- Domains — the mailbox domain list. A shared mailbox is anchored to exactly one domain; cross-domain sharing is not supported.
- Aliases — if you want one inbound address to deliver into one mailbox (rather than be visible to several users), an alias is the lighter-weight option. Aliases have no ACL surface at all.
- Email Relay > Virtual Recipients — the relay-side fan-out pattern. Sometimes a virtual recipient feeding two shared mailboxes (one per domain) is the right tool when a single role address needs to be visible to users on more than one mailbox domain.
- Mailbox Rules — Sieve rules can be configured on shared mailboxes the same way as on user mailboxes; the authentication path is the granting user, not the shared address.
- Authentication Settings — Submission-port auth that the Send-As flag piggybacks on, plus the LDAP backend that Dovecot looks up members against.