Mail account manager, or easy “Maacom”
I wrote this application for using into small-middle corporation. I wanted to write a simple classic object-oriented web application, that can be used as a training application.
The application wrote with
Work example of configuration Exim and Dovecot attached below the page.
Again I wanted to write it app with Ruby and Sinatra MVC (I love write program in Ruby OOP style), but then I thought about portability on Linux distributions (I use for work FreeBSD and latest releases of ruby gems) and then wrote with Perl and Mojolicious. “Life is Life”.
For postgres
# wget http://wiki.unix7.org/_media/dist/maacom-0.xx.tar.gz # tar xzvf maacom-0.xx.tar.gz # cd maacom-0.xx # ./configure --prefix=/usr/local --with-user=vmail --with-group=vmail # make # make install # cd /usr/local/etc/maacom # cp maacom.conf.example maacom.conf # cp maacom.crt.example maacom.crt # cp maacom.key.example maacom.key # cp maacom.pw.example maacom.pw # psql -U postgres -h localhost postgres < /usr/local/share/maacom/create-pg-db.sql # psql -U maacom -h localhost maacom < /usr/local/share/maacom/schema.sql # service maacom start
For systemd start like
# systemctl start maacom.service
After them connect as https://yourhost.com:8082
Default login/password is master/password.
For change password you can use Apache htpasswd util or simular
# htpasswd /usr/local/etc/maacom/maacom.pw yourlogin # htpasswd -D /usr/local/etc/maacom/maacom.pw master
# # $Id: maacom.conf,v 1.2 2017/12/10 20:42:53 root Exp root $ # loglevel = info dbname = maacom dbhost = 127.0.0.1 dblogin = maacom dbpassword = pazzword dbengine = postgres # or sqlite #EOF
Pairs key=value in config file override default configuration.
conffile = @app_confdir@/maacom.conf pwfile = @app_confdir@/maacom.pw logfile = @app_logdir@/maacom.log loglevel = info pidfile = @app_rundir@/maacom.pid crtfile = @app_confdir@/maacom.crt keyfile = @app_confdir@/maacom.key listenaddr4 = 0.0.0.0 listenaddr6 = [::] listenport = 8082 mxlog = /var/log/mail.log maildir = /var/vmail dbname = @app_datadir@/mail.db dbhost = dblogin = dbpassword = dbengine = sqlite3 group = @app_group@ user = @app_user@
BEGIN TRANSACTION; CREATE TABLE domains ( id int unique NOT NULL PRIMARY KEY, name text unique, size int DEFAULT 0, quota int DEFAULT 0 ); CREATE TABLE users ( id int unique NOT NULL PRIMARY KEY, name text, domain_id int, password text, hash text, size int DEFAULT 0, quota int DEFAULT 0 ); CREATE TABLE aliases ( id int unique NOT NULL PRIMARY KEY, name text, domain_id int, list text ); CREATE TABLE forwarded ( id int unique NOT NULL PRIMARY KEY, name text unique ); CREATE TABLE unwanted ( id int unique NOT NULL PRIMARY KEY, name text unique ); CREATE TABLE trusted ( id int unique NOT NULL PRIMARY KEY, name text unique ); COMMIT;
$ mkdir -p /var/maacom/mail.db $ sqlite3 /var/maacom/mail.db < schema.sql
create user maacom encrypted password 'password'; create database maacom owner maacom;
$ psql -U postgres -h localhost postgres < create-db.sql $ psql -U maacom -h localhost maacom < schema.sql
# # $Id: exim.conf,v 1.10 2016/10/08 07:25:40 root Exp root $ # primary_hostname = think.unix7.org local_interfaces = <; ::0 ; 0.0.0.0 hide pgsql_servers = 127.0.0.1/maacom/maacom/password domainlist local_domains = @ : $primary_hostname : \ ${lookup pgsql{SELECT name FROM domains \ WHERE name = '${quote_pgsql:${domain}}'}} ... acl_check_rcpt: accept hosts = : control = dkim_disable_verify accept authenticated = * control = dkim_disable_verify accept !authenticated = * domains = +local_domains drop !authenticated = * domains = !+local_domains message = $primary_hostname: Attempt to send mail for non-local domain $domain was rejected delay = 5s drop ... begin routers smtp: driver = dnslookup domains = ! +local_domains transport = smtp ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1 log_as_local = no no_more redirect: driver = redirect log_as_local = no allow_fail allow_defer data = ${lookup pgsql{\ SELECT list FROM aliases, domains \ WHERE aliases.name||'@'||domains.name = '${quote_pgsql:${local_part}@${domain}}' \ AND aliases.domain_id = domains.id}} more = yes unseen = ${lookup pgsql{\ SELECT 'yes' FROM users, domains \ WHERE users.name||'@'||domains.name = '${quote_pgsql:${local_part}@${domain}}' \ AND users.domain_id = domains.id LIMIT 1}{yes}{no}} virtual: driver = accept domains = +local_domains condition = ${lookup pgsql{\ SELECT 'yes' FROM users, domains \ WHERE users.name||'@'||domains.name = '${quote_pgsql:${local_part}@${domain}}' \ AND users.domain_id = domains.id LIMIT 1}{yes}{no}} transport = user user = vmail group = vmail more = yes ....
# # $Id: sql.conf,v 1.1 2017/12/10 14:28:23 root Exp root $ # #driver = sqlite #connect = /var/maacom/mail.db driver = pgsql connect = host=127.0.0.1 dbname=maacom user=maacom password=pazzword default_pass_scheme = PLAIN password_query = SELECT users.name AS username, \ domains.name AS domain, \ users.password AS password \ FROM users, domains \ WHERE users.name = '%n' \ AND domains.name = '%d' \ AND users.domain_id = domains.id \ LIMIT 1; user_query = SELECT '/var/vmail/%d/%n' AS home, \ 'maildir:/var/vmail/%d/%n' AS mail, \ 'vmail' AS uid, \ 'vmail' AS gid, \ '*:bytes=1073741824' AS quota_rule \ FROM users, domains \ WHERE users.name = '%n' \ AND domains.name = '%d' \ AND users.domain_id = domains.id \ LIMIT 1; iterate_query = SELECT users.name||'@'||domains.name AS username \ FROM users, domains \ WHERE users.domain_id = domains.id; #EOF
For using quota change string in SELECT
user_query = SELECT '/var/vmail/%d/%n' AS home, \ 'maildir:/var/vmail/%d/%n' AS mail, \ 'vmail' AS uid, \ 'vmail' AS gid, \ '*:bytes='||users.quota*1024*1024 AS quota_rule \ FROM users, domains \ WHERE users.name = '%n' \ AND domains.name = '%d' \ AND users.domain_id = domains.id \ LIMIT 1;
Check:
Dec 15 09:26:28 vbsd05 dovecot: lda(borodin@unix7.org): msgid=<20171215092549.69d43c83@gmail.com>: save failed to INBOX: Quota exceeded (mailbox for user is full)
More correct, of course, will set up a quota check in the MTA rules.
# # $Id$ # server { server_name mx.unix7.org; listen 80; listen [::]:80; return 301 https://$server_name$request_uri; } server { server_name mx.unix7.org; listen 443 ssl; listen [::]:443 ssl; ssl_certificate nginx.crt; ssl_certificate_key nginx.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; location / { proxy_pass https://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }