ive checked on my mac and get the public folders and there accessible on nethserver
just incase ive modified my configs in the past and forgot here is my read file and my dovecot.conf
read file
#!/usr/bin/perl
#
# Copyright (C) 2019 Nethesis S.r.l.
# http://www.nethesis.it - nethserver@nethesis.it
#
# This script is part of NethServer.
#
# NethServer is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or any later version.
#
# NethServer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NethServer. If not, see COPYING.
#
use strict;
use warnings;
use esmith::ConfigDB;
use JSON;
require '/usr/libexec/nethserver/api/lib/helper_functions.pl';
require '/usr/libexec/nethserver/api/nethserver-mail/lib/mail_functions.pl';
sub list_public_folders
{
my $expand = shift;
my %folders;
my @list = `/usr/bin/doveadm mailbox list -u vmail Public/*`;
my $junkFolder = esmith::ConfigDB->open_ro()->get_prop('dovecot', 'SpamFolder') || '';
foreach (@list) {
chomp;
my $name = substr($_, 7); # trim Public/ prefix
next if (index($name, '/') >= 0);
$folders{$name} = {
'name' => $name,
'type' => 'public',
'readonly' => ($name eq $junkFolder),
'displayname' => $name
};
if ($expand) {
$folders{$name}{'acls'} = get_folder_acls($name);
}
}
return \%folders;
}
my $input = readInput();
my $cmd = $input->{'action'};
my $ret = {};
if ($cmd eq 'list') {
$ret->{'builtin'} = [{"name" => "root", "type" => "builtin", "displayname" => "root"}];
$ret->{'users'} = [];
$ret->{'groups'} = [];
$ret->{'public'} = [];
my $expand = $input->{'expand'} || 0;
my $cdb = esmith::ConfigDB->open_ro();
my $adb = esmith::ConfigDB->open_ro('accounts');
my ($gdb, $quotas, $connectors, $quota_status);
if ($expand) {
$gdb = esmith::ConfigDB->open_ro('getmail');
$quotas = decode_json(`/usr/libexec/nethserver/mail-quota`);
$quota_status = $cdb->get_prop('dovecot', 'QuotaStatus');
}
my $users = safe_decode_json(`/usr/libexec/nethserver/list-users`, []);
my $dynamic = $cdb->get_prop('postfix', 'DynamicGroupAlias') || 'disabled';
if ($expand) {
if ($gdb) {
foreach my $gr ($gdb->get_all()) {
my $obj = {'type' => 'getmail', 'name' => $gr->key, 'props' => {}};
my %props = $gr->props;
my $account = $props{'Account'};
delete($props{'Account'});
$obj->{'props'} = \%props;
if (!$connectors->{$account}) {
$connectors->{$account} = [];
}
push($connectors->{$account}, $obj);
}
}
}
foreach (keys %$users) {
my $status = $adb->get_prop($_, 'MailStatus') || 'enabled';
$_ =~ m/(.*)\@(:*)/;
my $user = {
'name' => $_,
'displayname' => $1,
'type' => 'user'
};
if ($expand) {
$user->{'props'} = get_defaults('user', $cdb);
$user->{'quota'} = { 'percentage' => 0, 'messages' => 0, 'maximum' => 0, 'size' => 0};
$user->{'connectors'} = $connectors->{$_} ? $connectors->{$_} : {};
my $record = $adb->get($_) || undef;
if (defined($record)) {
# read config from db
my %props = $record->props;
$props{'MailSpamRetentionTime'} = substr($props{'MailSpamRetentionTime'} || '', 0, -1); # remove final 'd'
$props{'MailForwardAddress'} = [split(',', $props{'MailForwardAddress'} || '')];
# force custom quota to default if global quota is disabled
if ($props{'MailQuotaType'} && $quota_status eq 'disabled') {
$props{'MailQuotaType'} = 'default';
}
# express quota in GB
if ($props{'MailQuotaCustom'} && $props{'MailQuotaCustom'} ne 'unlimited') {
$props{'MailQuotaCustom'} = int($props{'MailQuotaCustom'}/10);
}
foreach my $k (keys %props) {
$user->{'props'}{$k} = $props{$k};
}
}
my $quota = $quotas->{$_} || undef;
if ($quota) {
$user->{'quota'}{'percentage'} = int($quota->{'perc'});
$user->{'quota'}{'messages'} = $quota->{'msg'};
$user->{'quota'}{'size'} = int($quota->{'size'})*1024;
$user->{'quota'}{'maximum'} = int($quota->{'max'})*1024;
}
push($ret->{'users'}, $user);
} else {
# add to flat list only if enabled
push($ret->{'users'}, $user) if ($status eq 'enabled');
}
}
my $folders = list_public_folders($expand);
# output group list
# if expanded == true -> the list is used under the groups mailboxes
# if expanded == false -> the list is user for ACL on public mailboxes
if ($dynamic eq 'enabled' || !$expand) {
my $groups = safe_decode_json(`/usr/libexec/nethserver/list-groups`, []);
foreach my $group (keys %$groups) {
$group =~ m/(.*)\@(:*)/;
my $obj = {'name' => $group, 'displayname' => $1, 'type' => 'group'};
my $status = $adb->get_prop($group, 'MailStatus') || 'enabled';
if ($expand) {
# a group is enabled if DynamicGroupAlias is enabled and the record on accounts db is not disabled
$obj->{'props'} = { 'MailStatus' => $status };
push($ret->{'groups'}, $obj);
} else {
# add to flat list only if enabled
push($ret->{'groups'}, $obj) if ($status eq 'enabled');
}
}
}
foreach my $folder (keys %$folders) {
push($ret->{'public'}, $folders->{$folder});
}
} elsif ($cmd eq 'configuration') {
my $config = {};
my $cdb = esmith::ConfigDB->open_ro();
my $dovecot = $cdb->get('dovecot');
foreach (qw(AdminIsMaster DeletedToTrash ImapStatus LogActions MaxUserConnectionsPerIp PopStatus QuotaStatus)) {
$config->{$_} = $dovecot->prop($_);
}
$config->{'QuotaDefaultSize'} = int($dovecot->prop('QuotaDefaultSize')/10);
my $retention = $dovecot->prop('SpamRetentionTime');
if ($retention eq 'infinite') {
$config->{'SpamRetentionTime'} = "-1";
} else {
$config->{'SpamRetentionTime'} = substr($retention, 0, -1); # remove 'd' suffix
}
$config->{'SpamFolder'} = ($dovecot->prop('SpamFolder') ne '') ? 'enabled' : 'disabled';
$config->{'TlsSecurity'} = ($dovecot->prop('TlsSecurity') eq 'required') ? 'enabled' : 'disabled';
$config->{'DynamicGroupAlias'} = $cdb->get_prop('postfix', 'DynamicGroupAlias') || 'disabled';
$ret->{'configuration'} = $config;
} elsif ($cmd eq 'aliases') {
my $name = $input->{'name'};
my $type = $input->{'type'};
my @aliases;
my $adb = esmith::ConfigDB->open_ro('accounts');
my $ddb = esmith::ConfigDB->open_ro('domains');
my $cdb = esmith::ConfigDB->open_ro();
my $dynamic = $cdb->get_prop('postfix', 'DynamicGroupAlias') || 'disabled';
my $domain = $cdb->get_value('DomainName');
my $public_domain = defined($ddb->get($domain));
# add built-in alias if local domain is also a mail domain
if ($type eq 'user' && $public_domain) {
# user must be added only if MailStatus == enabled
my $mail_status = $adb->get_prop($name, 'MailStatus') || 'enabled';
push(@aliases, $name) if ($mail_status eq 'enabled');
}
if ($type eq 'group') {
if ($dynamic eq 'enabled' && $public_domain) {
push(@aliases, $name);
} else {
$name =~ m/(.*)\@(:*)/;
$name = "$name|vmail\\+".$1;
}
}
if ($type eq 'public') {
$name = "vmail\\+$name\$";
}
my @domains = $ddb->get_all_by_prop('type' => 'domain');
foreach my $pseudonym ($adb->get_all_by_prop('type' => 'pseudonym')) {
my @accounts = split(",", $pseudonym->prop('Account') || '');
foreach my $a (@accounts) {
if ($a =~ m/$name/) {
# expand wildcard
if ($pseudonym->key =~ m/\@$/) {
foreach my $d (@domains) {
push(@aliases, $pseudonym->key.$d->key);
}
} else {
push(@aliases, $pseudonym->key);
}
}
}
}
$ret->{'aliases'} = \@aliases;
} else {
error();
}
print encode_json($ret);
dovecot.conf
# ================= DO NOT MODIFY THIS FILE =================
#
# Manual changes will be lost when this file is regenerated.
#
# Please read the developer's guide, which is available
# at NethServer official site: https://www.nethserver.org
#
#
#
# disable debug
#
debug_log_path = /dev/null
mbox_write_locks = fcntl
ssl_cert = </etc/pki/dovecot/certs/dovecot.pem
ssl_key = </etc/pki/dovecot/private/dovecot.pem
mail_shared_explicit_inbox = yes
#
# TLS
# cipher selection 2020-05-10 Only TLS 1.2 (RSA and ECC certificate)
#
ssl_dh_parameters_length = 2048
ssl_protocols = !SSLv3 !SSLv2 !TLSv1 !TLSv1.1
ssl_cipher_list = kEECDH:+kEECDH+SHA:kEDH:+kEDH+SHA:+kEDH+CAMELLIA:kECDH:+kECDH+SHA:kRSA:+kRSA+SHA:+kRSA+CAMELLIA:!aNULL:!eNULL:!SSLv2:!SSLv3:!RC4:!MD5:!DES:!EXP:!SEED:!IDEA:!3DES
ssl_prefer_server_ciphers = yes
#
# 10environment
#
import_environment = TZ KRB5CCNAME
#
# Limits
#
default_process_limit = 400
mail_max_userip_connections = 12
service anvil {
client_limit = 1603
}
service auth {
client_limit = 2400
}
#
# 10limits_local
#
remote 127.0.0.1 {
mail_max_userip_connections = 60
}
#
# 20protocols -- configure access to mailboxes
#
protocols = imap lmtp sieve pop3
disable_plaintext_auth = no
# inet_listener control for IMAP protocol. Refs #1396
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
}
}
#
# 20users -- configure user authentication and storage
#
first_valid_uid = 981
last_valid_uid = 981
mail_uid = vmail
mail_gid = vmail
# See http://wiki2.dovecot.org/Authentication/MasterUsers
auth_master_user_separator = *
passdb {
driver = passwd-file
args = /etc/dovecot/master-users
master = yes
}
# The list of disabled user accounts
passdb {
driver = passwd-file
args = /etc/dovecot/deny.passwd
deny = yes
}
# Authenticate users against PAM
passdb {
driver = pam
args = max_requests=100 failure_show_msg=yes blocking=yes
}
# LDA/IMAP access for users in /etc/passwd without @domain in username
userdb {
driver = passwd-file
args = username_format=%Ln /etc/dovecot/imap.passwd
override_fields = uid=981 gid=978 home=/var/lib/nethserver/vmail/%Ln
}
# User custom quota userdb override:
# Global quota is disabled
# LDA/IMAP access for users from SSSD/NSS
userdb {
skip = found
driver = passwd
override_fields = uid=981 gid=978 home=/var/lib/nethserver/vmail/%u
}
# catch-all mailbox
# disabled
# Location of mailboxes:
mail_location = maildir:~/Maildir
#
# 25user-action_logs
#
mail_plugins = $mail_plugins mail_log notify
plugin {
mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename mailbox_create flag_change append
mail_log_fields = uid box msgid from subject flags
}
#
# 30quota -- uncomment to load the quota plugin globally
#
# mail_plugins = $mail_plugins quota
#
# Namespace setup
#
# Private mailboxes
namespace ROOT {
type = private
separator = /
prefix =
# location defaults to mail_location.
inbox = yes
subscriptions = yes
# Commonly used folders:
mailbox Trash {
special_use = \Trash
auto = no
}
mailbox Drafts {
special_use = \Drafts
auto = no
}
mailbox Sent {
special_use = \Sent
auto = no
}
mailbox "Sent Messages" {
special_use = \Sent
auto = no
}
}
# Shared mailboxes are enabled
namespace SHARED_USERS {
type = shared
disabled = no
separator = /
prefix = Shared/%%n@domain.com/
location = maildir:/var/lib/nethserver/vmail/%%u/Maildir
subscriptions = no
list = children
}
# Public mailboxes
namespace PUBLIC {
type = public
separator = /
prefix = Public/
subscriptions = no
list = children
location = maildir:/var/lib/nethserver/vmail/vmail/Maildir:INDEXPVT=~/Maildir/public
}
# Enable acl plugin for shared mailboxes,
# and listescape to extend allowable characters in mailbox names
mail_plugins = $mail_plugins acl listescape fts fts_lucene
protocol imap {
mail_plugins = $mail_plugins imap_acl
}
plugin {
acl = vfile
acl_shared_dict = file:/var/lib/nethserver/vmail/shared-mailboxes.db
fts = lucene
fts_lucene = whitespace_chars=@.
}
service dict {
unix_listener dict {
mode = 0600
user = vmail
}
}
service imap-login {
unix_listener imap-ipc {
group = root
user = $default_internal_user
mode = 0600
}
}
# auth_debug = yes
# auth_verbose = yes
#
# 40postlogin (imap, managesieve)
#
service imap {
executable = imap imap-postlogin
}
service imap-postlogin {
executable = script-login /usr/libexec/nethserver/dovecot-postlogin
user = $default_internal_user
unix_listener imap-postlogin {
}
}
service managesieve {
executable = managesieve sieve-postlogin
}
service sieve-postlogin {
executable = script-login /usr/libexec/nethserver/dovecot-postlogin
user = $default_internal_user
unix_listener sieve-postlogin {
}
}
service pop3 {
executable = pop3 pop3-postlogin
}
service pop3-postlogin {
executable = script-login /usr/libexec/nethserver/dovecot-postlogin
user = $default_internal_user
unix_listener pop3-postlogin {
}
}
#
# 50deletedtotrash dovecot plugin
#
protocol imap {
mail_plugins = $mail_plugins deleted_to_trash
}
plugin {
deleted_to_trash_folder = Trash
}
#
# Quota configuration is disabled
#
#
# 50spam_training
#
protocol imap {
mail_plugins = $mail_plugins imap_sieve
}
plugin {
sieve_plugins = sieve_extprograms sieve_imapsieve
sieve_pipe_bin_dir = /usr/libexec/nethserver/imapsieve
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
# From elsewhere to Spam folder
imapsieve_mailbox1_name = Junk
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/var/lib/nethserver/sieve-scripts/report-spam.sieve
# From Spam folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Junk
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/var/lib/nethserver/sieve-scripts/report-ham.sieve
}
#
# 40spamfolder
#
namespace ROOT {
# Our junkmail folder:
mailbox Junk {
special_use = \Junk
auto = subscribe
}
}
#
# 50vsz_limit
#
# Using default value for default_vsz_limit
#
# LDA message delivery for getmail
#
protocol lda {
mail_plugins = $mail_plugins sieve
}
#
# LMTP server for message delivery
#
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
recipient_delimiter = +
lmtp_save_to_detail_mailbox = yes
# Global sieve script, executed BEFORE user's private scripts:
plugin {
sieve_before = /var/lib/nethserver/sieve-scripts/before.sieve
sieve_after = /var/lib/nethserver/sieve-scripts/after.sieve
sieve_extensions = +imapflags +editheader
}
service lmtp {
user = vmail
client_limit = 1
unix_listener lmtp {
user = vmail
group = vmail
mode = 00660
}
}
service auth {
unix_listener auth-userdb {
mode = 00660
# user = <default>
group = vmail
}
}
#
# Postfix to Dovecot communcations for SMTP AUTH
# See http://www.postfix.org/SASL_README.html
#
service auth {
unix_listener smtpauth {
path = /var/spool/postfix/private/smtpauth
mode = 00660
user = postfix
group = postfix
}
}
auth_mechanisms = plain login gssapi
auth_krb5_keytab = /var/lib/dovecot/krb5.keytab
also not sure if it makes a difference but my mac is older and runs high sierra (thought id mention incase it works on mine but not on yours if yours is newer and apple changed the code)