Postfix keeps deliver incoming mails to ~/Maildir

Dear Virtualmins,

I want to have all mails stored in the external location.

However changing Dovecot’s mail_location in /etc/dovecot/conf.d/10-mail.conf does the job but incoming email always delivered to user’s home directory ~/Maildir by Postfix.

Actually changing manually changing user directory actually works but it required me to change each of them. So might be somewhere to configure in the Postfix but I have no ideas and have been googling for few days.

Things I have done is trying to use LMTP protocol with Sieve to filter and deliver incoming mail to the external location with invidual directory. Unfortunately, I almost got LMTP to works but end up stuck at “User’s doesn’t” exist error.

I not sure does dovecot supports keep all incoming mails in local (~/Maildir) and move read and old mails to alternative storage (/mnt/data/%d/%n). If this possible I might gaining benefits on performance on reading new mail.

Otherwise I’m keen for any possible workaround!

/etc/dovecot/conf.d/10-mail.conf

...
#   mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
#
# <doc/wiki/MailLocation.txt>
#
#mail_location = maildir:~/Maildir
mail_location = /mnt/data/%d/%n

# If you need to set multiple mailbox locations or want to change default
...

/etc/postfix/main.cf

alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
allow_percent_hack = no
append_dot_mydomain = no
biff = no
broken_sasl_auth_clients = yes
compatibility_level = 3.6
header_checks = regexp:/etc/postfix/list_unsub_header
home_mailbox = Maildir/
inet_protocols = ipv4
mailbox_command =
mailbox_size_limit = 0
message_size_limit = 26214400
milter_default_action = accept
mydestination = $myhostname, localhost.$myorigin, localhost, $myorigin
myhostname = server.example.com
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mynetworks_style = subnet
myorigin = /etc/mailname
non_smtpd_milters = inet:localhost:8891
readme_directory = no
recipient_delimiter = +
resolve_dequoted_address = no
sender_bcc_maps = hash:/etc/postfix/bcc
sender_dependent_default_transport_maps = hash:/etc/postfix/dependent
smtp_dns_support_level = dnssec
smtp_host_lookup = dns
smtp_tls_CApath = /etc/ssl/certs
smtp_tls_security_level = dane
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
smtpd_milters = inet:localhost:8891
smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination check_policy_service inet:127.0.0.1:10023
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_security_level = may
tls_server_sni_maps = hash:/etc/postfix/sni_map
virtual_alias_maps = hash:/etc/postfix/virtual
SYSTEM INFORMATION
OS type and version Ubuntu 22.04 LTS
Virtualmin version 7.7

Do you have experience with virtualmin as mail directories are done a virtual server basis (different locations). What you trying to do can break virtualmin.

Hi @stefan1959 ,

No and today I found an alternative workaround with “Command to run after making changes to an alias” under “System Settings > Virtualmin Configuration > Actions upon server and user creation”.

So I wrote a very simple script without any checking conditions for testing purposes. This script is to change home dir for any new user is created. However, I got stuck on passing the variables during the user creation.

Variables listing is getting from here: Template Variable Listing – Virtualmin

#!/bin/sh

# Variables
datetime=$(date +'%m %d %Y %H:%M:%S'):

# Initialize
echo $datetime Loaded change directory on create script! >> /var/log/custom-script.log

# Output data
mailbox=$MAILBOX #$VIRTUALSERVER_MAILBOX
email=$EMAIL #$VIRTUALSERVER_EMAIL
domain=$(echo "$email" | cut -d "@" -f 2)
echo $datetime mailbox=$mailbox email=$email domain=$domain >> /var/log/custom-script.log

# Define the new directory path
new_directory="/mnt/data/$domain/$mailbox"
echo $datetime Directory is now set to $new_directory >> /var/log/custom-script.log

# Change the user's home directory
usermod -m -d "$new_directory" "$email"
echo $datetime $(cat /etc/passwd | grep "$email") >> /var/log/custom-script.log

But output data is always return an empty string. Any thoughts?

Hi,

I not sure if this is the permanent solution for me.

The above post with Command to run after making changes to an alias is not working for me. I couldn’t pass the variables when creating user or I do not know how to pass it.

? say It can make use of the environment variables ALIAS_FROM, ALIAS_TO and ALIAS_ACTION to determine what alias is being changed and what is happening to it. I thought it is like if [ $VIRTUALSERVER_ACTION == MODIFY_DOMAIN ] then and I try with if [ ALIAS_ACTION == ADD_UER ] then or something. But it just don’t work and 2 problems here, lack of documentation and it will excute 2 times.

So I’ve created another bash script with more tasks like remove the old directory and so on. Then hardcoded and pass the variables to run the script everytime when I create new users in save-user.cgi under /usr/share/webmin/virtual-server/. I place it after &release_lock_mail($d) because I’ve encountered problem on changing dir with usermod -h -d.

save-user.cgi

...
    &release_lock_unix($d);
    &release_lock_mail($d);
    &webmin_log($in{'new'} ? "create" : "modify", "user",
        &remove_userdom($user->{'user'}, $d), $user);
}

# Somewhere around here
if ($in{'new'} && $d) {
    system("/home/user/custom.sh", $user->{'mailbox'} , $user->{'email'}, $user->{'home'});
}
...

custom.sh

#!/bin/sh

# Get current date and time
datetime="$(date +'%m %d %Y %H:%M:%S'):"

# Initialize
echo "" >> /var/log/custom-script.log
echo "" >> /var/log/custom-script.log
echo "" >> /var/log/custom-script.log
echo "$datetime Script loaded!" >> /var/log/custom-script.log

# Variables
username="$1" # Username
email="$2" # Email
domain="$(echo $email | cut -d '@' -f 2)" # Domain name
home="$3" # Directory

# Print
echo "$datetime Variables received: $username, $email, $domain!" >> /var/log/custom-script.log
echo "$datetime New user created: $2!" >> /var/log/custom-script.log

# Define the new directory path
new_directory="/mnt/data/$domain/$username"

# Print
echo "$datetime Directory is now set to $new_directory" >> /var/log/custom-script.log

# Change the user's home directory
usermod -m -d $new_directory $email

# Print
echo "$datetime User $username's directory changed to $(cat /etc/passwd | grep $email | cut -d ':' -f 6 )" >> /var/log/custom-script.log

# Move existing data to new directory (If any)
rsync -az --progress --partial "$home/" "$new_directory"

# Print
echo "$datetime Rsynced data to $new_directory" >> /var/log/custom-script.log
echo "$datetime $(ls $new_directory)" >> /var/log/custom-script.log

# Delete old directory
rm -r $home

# Print
echo "$datetime Removed $username's old directory $home" >> /var/log/custom-script.log
echo "$datetime Completed!" >> /var/log/custom-script.log

Correct me if I’m wrong and if there’s a better approach.

This may get get over written with future updates. Not custom i guess

Hi @stefan1959 ,

Yeah, I have no solution for now. Guess it be will my temporary solution and hopefully Virtualmin staff can do something about this.

The purpose of doing this is to save the cost on storage. I mounted my own NAS into the server so I can actually store mail data there.

Of course I can change every user directory in the Webmin, but it required manual work and it can be tedious and painful for my client.

Sorry I thought this was virtualmin :slight_smile:

Can’'t use just mount the NAS in the location on the /var/mail, the you don’t need to change config.

1 Like

Hi @stefan1959 ,

I can but I don’t know how to setup on postfix and dovecot to use mail data on /var/mail. :sweat_smile:

I should of said Maildir. Or create symlinks

I haven’t read everything on this topic, but since you’re using the postfix local delivery agent (rather than the usual Virtualmin default of procmail), have you read the documentation for it? Postfix manual - local(8)

You can set mail_spool_directory to determine where mail ends up, though you’re trying to do very unusual stuff. I dunno if the very basic delivery agent provided by Postfix will do what you want. There are many delivery agents to choose from; Dovecot has one that’s pretty good and flexible, procmail is the one we use in Virtualmin.

I would really love to have the ability to use Cyrus as the delivery agent. It has so many features including a central mail store, built in replication and load balancing, caldav and cardDAV. It doesn’t even need local users, everything can be purely virtual. 20 years ago I was using ispman. It used ldap and Cyrus and was wonderful but the group supporting it ended up folding. Imagine built in address book and calendar support! Crazy right? Oh and also server side filtering with sieve no extra work needed.

Maybe create a new topic, this is old and I think your off topic, maybe in the Blue Skies section.

2 Likes